<div dir="auto">That's an idea that could be added to my thread "dialects of python" in order to compile some fancy or specific syntax to regular python.</div><br><div class="gmail_quote"><div dir="ltr">Le sam. 22 sept. 2018 à 13:53, Lee Braiden <<a href="mailto:leebraid@gmail.com" target="_blank" rel="noreferrer">leebraid@gmail.com</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">Could I get some feedback on this?  I'd like to know if anyone thinks it might make it through the pep process before spending too much (more) time on it.  That said, it seems valuable to me, and I'm willing to put in the time, of course, IF it has a chance.<div><br></div><div><div><div>---------------------------</div></div><div><br></div><div>Problem:</div><div><br></div><div>    Due to (biggest python WTF) (Problem 1), which prevents actual default argument values being set in a function signature, many</div><div>    functions look like:</div><div><br></div><div>        > def teleport(from, to, passenger, hitchhiker=None, food_accessory=None, comfort_accessory=None):</div><div>        >     if hitchhiker is None:</div><div>        >         hitchhiker = Fly()</div><div>        ></div><div>        >     if food_accessory is None:</div><div>        >         food_accessory = Cheeseburger()</div><div>        ></div><div>        >     if comfort_accessory is None:</div><div>        >         comfort_accessory = Towel()</div><div>        ></div><div>        >     ...</div><div><br></div><div>    This None checking and setting is unwieldy (Problem 2) boilerplate, which is responsible for many extra lines of code in python</div><div>    (Problem 3), and tends to distract from the real code (Problem 4) in a function.</div><div><br></div><div>    To reduce boilerplate, a ternary or binary expression can be used:</div><div><br></div><div>        > def teleport(from, to, passenger, hitchhiker=None, accessories=[]):</div><div>        >     hitchhiker = hitchhiker if hitchhiker or Fly()                   # Existing Solution A</div><div><br></div><div>        > def teleport(from, to, passenger, hitchhiker=None, accessories=[]):</div><div>        >    hitchhiker = hitchhiker or Fly()                                 # Existing Solution B</div><div><br></div><div>    These help, but are still quite repetitive:</div><div><br></div><div>    * Existing Solution A is often avoided simply because many Pythonistas dislike tenery expressions (perhaps due to</div><div>      readability or hidden code branch concerns), and can quickly become unwieldy when the new value (Fly()) is a more</div><div>      complex expression, such as a list comprehension:</div><div><br></div><div>        > def teleport(from, to, passenger, hitchhiker=None, accessories=[]):</div><div>        >    hitchhiker = hitchhiker if hitchhiker or filter(lambda h: not h.already_hitching(), available_hitchhikers)[0]</div><div><br></div><div>    * Existing Solution B is less unwieldy (solving Problem 2), yet still suffers from repetition (Problems 2, 3, and 4).</div><div><br></div><div>    In a similar scenario, when we want to populate an empty list (say, accesories), we could write:</div><div><br></div><div>        > accessories |= [Cheeseburger(), Towel()]                              # Almost-Solution C</div><div><br></div><div>    However, this is not actually a solution, because:</div><div><br></div><div>        * The inplace-or (|=) operator is not provided for None in python:</div><div><br></div><div>          > food_accessor = None</div><div>          > food_accessory |= Cheeseburger()</div><div><br></div><div>          Traceback (most recent call last):</div><div>          File "<stdin>", line 1, in <module></div><div>          TypeError: unsupported operand type(s) for |=: 'NoneType' and 'Cheeseburger'</div><div><br></div><div>          This could be added, but would not solve the issue, because:</div><div><br></div><div>        * If an non-default (non-None) argument value WERE provided, we be would modifying</div><div>          the argument unintentionally:</div><div><br></div><div>            > class Larry:</div><div>            >     def __ior__(self, other):</div><div>            >         print("{} modified".format(self))</div><div>            ></div><div>            > teleport(..., hitchhiker=Larry(), ...)</div><div>            <__main__.Larry object at 0x7f1ad9828be0> modified</div><div><br></div><div>    And so Problems 1,2,3, and 4 are compounded.</div><div><br></div><div>Proposal:</div><div><br></div><div>    The addition of a ?= operator could provide an elegant solution:</div><div><br></div><div>        > def teleport(from, to, hitchiker=None, food_accessory=None, comfort_accessory=None):</div><div>        >     hitchhiker ?= Fly()</div><div>        >     food_accessory ?= Cheeseburger()</div><div>        >     comfort_accessory ?= Towel()</div><div><br></div><div>    In these examples,</div><div><br></div><div>        > a = None</div><div>        > a ?= b</div><div><br></div><div>        > c = [1, 2]</div><div>        > c ?= d</div><div><br></div><div>    Would be equivalent to (assuming ?= was called __ielse__):</div><div><br></div><div>        > class ExtendedNone(NoneType)</div><div>        >     def __ielse__(self, other):</div><div>        >         return other</div><div>        ></div><div>        > class ielse_list(list):</div><div>        >     def __ielse__(self, other):</div><div>        >         return self</div><div>        ></div><div>        > None = ExtendedNone()</div><div>        ></div><div>        > a = None</div><div>        > a = a.__ielse__(b)</div><div>        ></div><div>        > c = iff_list([1, 2])</div><div>        > c = a.__ielse__(d)</div><div><br></div><div>    Although explicitly provided for list above, this ielse operator could be defined</div><div>    (again, as `return other` for NoneType only, but defaulted to `return self` for</div><div>    all other values of `a`, requiring very little implementation effort or intrusion</div><div>    into other types.</div></div><div><br></div><div>Possible interaction with typing</div><div><br></div><div>    It may be also possible to define a ? suffix on function arguments, so that:</div><div><br></div><div>        > def func(a?):</div><div>        >     a ?= [1,2]<br><br></div><div>     greatly shorting the current verbose form:<br></div><div><br>         > from typing import Optional<br>         > </div><div>         > def func(a = None : Optional[Any])):</div><div>         >     a = [1,2] if a is None else a</div><div><br><div>    and equivalent to:<br><br>        > from typing import Optional<br>        ><br>        > def func(a: Optional[Any]):<br>        >     a = a.__ielse__([1,2])</div></div><div><br></div><div>Possible alternatives:</div><div><br></div><div>    * The __ielse__ name is highly debatable.  Alternatives such as __iif__ (inplace if), __imaybe__, __isomeor__ (borrowing from Rusts's Some/None terminology, and reflecting the intended use as in relation to None types, DB nulls, and similar void-like values).<br><br>    * The ? function argument suffix is not necessary to implement the core ?= proposal.<br><br>    * If the ? function argument suffix  is implemented, implementation via typing.Optional is not necessary; it could also be simply implemented so that:</div><div><br></div><div>        > def f(a?):<br></div><div>        >     ...</div><div><br></div><div>    is equivalent to:</div><div><br></div><div>        > def f(a=None):</div><div><div>        >     ...</div></div><div><br></div><div><br></div><div>---------------------------</div><div><br></div><div>Feedback would be much appreciated.</div><div><br></div><div>-- </div><div>Lee</div><div><br></div></div></div></div></div></div></div>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" rel="noreferrer noreferrer" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>