On Wed, May 20, 2020 at 12:23 PM Rob Cliffe via Python-ideas <python-ideas@python.org> wrote:
On 17/05/2020 20:17, James Lu wrote:
Many a python programmer have tired to see code written like:
def bar(a1, a2, options=None): if options is None: options = {} ... # rest of function
syntax if argument is not passed, evaluate {} and store to options def foo(options:={}): pass syntax if argument is not passed or is None, evaluate {} and store to options* def foo(options?={}): pass
The Zen of Python states "there shouldn't be two ways to do the same thing."
Thus, only one of ":=" or "?=" should be adopted. They should be evalued on: - Which encourages writing better code? - Which catches mistakes easier?
Do we want to encourage callers to pass None to indicate default arguments?
spam = { data: True } if arg else None bar(a1, a2, param=spam)
versus
bar(a1, a2, { data: True }) if arg else bar(a1, a2)
versus
_ = foo.curry(a1, a2) _({data: True}) if arg else _(a1, a2)
Since Python is a strongly typed language, it seems more consistent to me that this code should throw an error: def getoptions(): ... # code to get options # whoops! missing return statement #return os.environ foo(a1, a2, param=getoptions())
:= should be adopted because it catches mistakes more quickly.
On the other hand, ?= replaces the "if kwarg is not None: kwarg = ..." idiom.
(I propose adopting only ":=". I show "?=" as a strawman.) This seems to have some merit. It is quite common, I believe, to want an argument's default value to be evaluated on each call (and beginners are often confused when it isn't), and to use the idiom James quotes:
def bar(a1, a2, options=None): if options is None: options = {}
Allowing `options:={}` will confuse beginners, but many of them are already confused.:-)
It would be a major breaking change if ALL default arguments were late-evaluated. Errors wouldn't be caught till later, performance would suffer, and semantics would change. More plausible would be to have a syntactic adornment that triggers this, making it completely opt-in. The semantics would be subtly different from the None variety, being more like the similar variant involving a sentinel: def spam(x, y, ham=object()): if ham is spam.__defaults__[-1]: ham = {} But with actual language support, the sentinel object wouldn't be visible anywhere, and anything involving docstrings would show the original text used, which would be WAY more helpful. This has been proposed frequently and never gone far, and I think it's because nobody can settle on a really good syntax for it. Consider: # Looks like an old Py2 repr def spam(x, y, ham=`{}`): # Way too magical, although it parses currently and might # be done with the help of a magic built-in def spam(x, y, ham=LATE%{}): # wut? def spam(x, y, ham=>{}): # even worse def spam(x, y, ham=->{}): etc etc etc. There are lots of bad syntaxes and very few that have any merit. I'd love to have this as a feature, though. ChrisA