>From what I've seen so far, I'm -0 on this. I understand the pattern it addresses, but it doesn't feel all that common, nor that hard to address with the existing sentinel-check pattern alien in the PEP draft.
This just doesn't feel big enough to merit it's own syntax. ... On the other hand, if this could express a much more general deferred computation, I'd be really enthusiastic (subject to syntax and behavioral details). However, I recognize that a new general "dynamically scoped lambda" would indeed have a lot of edge cases. On Sat, Oct 23, 2021, 8:15 PM Chris Angelico <ros...@gmail.com> wrote: > Incorporates comments from the thread we just had. > > Is anyone interested in coauthoring this with me? Anyone who has > strong interest in seeing this happen - whether you've been around the > Python lists for years, or you're new and interested in getting > involved for the first time, or anywhere in between! > > https://www.python.org/dev/peps/pep-0671/ > > PEP: 671 > Title: Syntax for late-bound function argument defaults > Author: Chris Angelico <ros...@gmail.com> > Status: Draft > Type: Standards Track > Content-Type: text/x-rst > Created: 24-Oct-2021 > Python-Version: 3.11 > Post-History: 24-Oct-2021 > > > Abstract > ======== > > Function parameters can have default values which are calculated during > function definition and saved. This proposal introduces a new form of > argument default, defined by an expression to be evaluated at function > call time. > > > Motivation > ========== > > Optional function arguments, if omitted, often have some sort of logical > default value. When this value depends on other arguments, or needs to be > reevaluated each function call, there is currently no clean way to state > this in the function header. > > Currently-legal idioms for this include:: > > # Very common: Use None and replace it in the function > def bisect_right(a, x, lo=0, hi=None, *, key=None): > if hi is None: > hi = len(a) > > # Also well known: Use a unique custom sentinel object > _USE_GLOBAL_DEFAULT = object() > def connect(timeout=_USE_GLOBAL_DEFAULT): > if timeout is _USE_GLOBAL_DEFAULT: > timeout = default_timeout > > # Unusual: Accept star-args and then validate > def add_item(item, *optional_target): > if not optional_target: > target = [] > else: > target = optional_target[0] > > In each form, ``help(function)`` fails to show the true default value. Each > one has additional problems, too; using ``None`` is only valid if None is > not > itself a plausible function parameter, the custom sentinel requires a > global > constant; and use of star-args implies that more than one argument could be > given. > > Specification > ============= > > Function default arguments can be defined using the new ``=>`` notation:: > > def bisect_right(a, x, lo=0, hi=>len(a), *, key=None): > def connect(timeout=>default_timeout): > def add_item(item, target=>[]): > > The expression is saved in its source code form for the purpose of > inspection, > and bytecode to evaluate it is prepended to the function's body. > > Notably, the expression is evaluated in the function's run-time scope, NOT > the > scope in which the function was defined (as are early-bound defaults). This > allows the expression to refer to other arguments. > > Self-referential expressions will result in UnboundLocalError:: > > def spam(eggs=>eggs): # Nope > > Multiple late-bound arguments are evaluated from left to right, and can > refer > to previously-calculated values. Order is defined by the function, > regardless > of the order in which keyword arguments may be passed. > > > Choice of spelling > ------------------ > > Our chief syntax proposal is ``name=>expression`` -- our two syntax > proposals > ... ahem. Amongst our potential syntaxes are:: > > def bisect(a, hi=>len(a)): > def bisect(a, hi=:len(a)): > def bisect(a, hi?=len(a)): > def bisect(a, hi!=len(a)): > def bisect(a, hi=\len(a)): > def bisect(a, hi=`len(a)`): > def bisect(a, hi=@len(a)): > > Since default arguments behave largely the same whether they're early or > late > bound, the preferred syntax is very similar to the existing early-bind > syntax. > The alternatives offer little advantage over the preferred one. > > How to Teach This > ================= > > Early-bound default arguments should always be taught first, as they are > the > simpler and more efficient way to evaluate arguments. Building on them, > late > bound arguments are broadly equivalent to code at the top of the function:: > > def add_item(item, target=>[]): > > # Equivalent pseudocode: > def add_item(item, target=<OPTIONAL>): > if target was omitted: target = [] > > > Open Issues > =========== > > - yield/await? Will they cause problems? Might end up being a non-issue. > > - annotations? They go before the default, so is there any way an anno > could > want to end with ``=>``? > > > References > ========== > > > Copyright > ========= > > This document is placed in the public domain or under the > CC0-1.0-Universal license, whichever is more permissive. > _______________________________________________ > Python-ideas mailing list -- python-ideas@python.org > To unsubscribe send an email to python-ideas-le...@python.org > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > Message archived at > https://mail.python.org/archives/list/python-ideas@python.org/message/KR2TMLPFR7NHDZCDOS6VTNWDKZQQJN3V/ > Code of Conduct: http://python.org/psf/codeofconduct/ >
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/JSPTTDFLNZSVXAHQ4I4FAUWYE7VC2M4U/ Code of Conduct: http://python.org/psf/codeofconduct/