On 24/05/2020 21:03, Dominik Vilsmeier wrote:
On 24.05.20 18:34, Alex Hall wrote:
OK, let's forget the colon. The point is just to have some kind of
'modifier' on the default value to say 'this is evaluated on each
function call', while still having something that looks like
`arg=<default>`. Maybe something like:
def func(options=from {}):
It looks like the most common use case for this is to deal with
mutable defaults, so what is needed is some way to specify a default
factory, similar to `collections.defaultdict(list)` or
`dataclasses.field(default_factory=list)`. This can be handled by a
decorator, e.g. by manually supplying the factories or perhaps
inferring them from type annotations:
@supply_defaults
def foo(x: list = None, y: dict = None):
print(x, y) # [], {}
@supply_defaults(x=list, y=dict)
def bar(x=None, y=None):
print(x, y) # [], {}
That's very clever, but if you compare it with the status quo:
def bar(x=None, y=None):
if x is None: x = []
if y is None: y={}
it doesn't save a lot of typing and will be far more obscure to newbies
who may not know about decorators. (And if other decorators are used on the
same function, the fog only thickens.) They may not know why the
contorted way
of assigning to x and y is necessary, but they can follow what it does.
Even someone familiar with decorators will have to look up
supply_defaults and
find out what it does (and it jolly well ought to be copiously
documented :-)).
Trying to do some blue-sky thinking, I have tried to come up with other
ideas,
but have not found anything very convincing, e.g.:
Idea: Invent a new kind of string which behave like f-strings, called
say g-strings.
Add a rule that if the default value of an argument is (an
expression containing) a g-string,
the default value is recalculated every time the function is
called and a value for that argument is not passed.
So:
def bar(x=g'{ [] }], y=g'{ {} }'):
Cons: I could list a couple myself, no doubt others can think of many more.
No, forget fudges.
I think what is needed is to take the bull by the horns and add some
*new syntax*
that says "this default value should be (re)calculated every time it is
needed".
Personally I don't think the walrus operator is too bad:
def bar(x:=[], y:={}):
It's concise, and arguably will largely only confuse people who are
already confused.
It AKAICS introduces no ambiguity (it's currently a syntax error).
It *is* somewhat arbitrary (in one context the walrus means 'this
assignment becomes an expression',
in another it means 'recalculate this expression every time it's needed').
But hey, you could say the same about colon, comma, parentheses, braces
and what-have-you.
It is IMO practical.
It needs no new keywords.
Other syntaxes are of course possible, but for me, in this case,
conciseness is a virtue. YMMV.
(Possibly heretical) Thought:
ISTM that when the decision was made that arg default values should be
evaluated
once, at function definition time,
rather than
every time the function is called and the default needs to be
supplied
that that was the *wrong* decision.
There may have been what seemed good reasons for it at the time (can
anyone point me
to any relevant discussions, or is this too far back in the Python
primeval soup?).
But it is a constant surprise to newbies (and sometimes not-so-newbies).
As is attested to by the number of web pages on this topic. (Many of
them defend
the status quo and explain that it's really quite logical - but why does
the status quo
*need* to be defended quite so vigorously?)
I realise that it's far too late to change this behaviour in Python 3.
And also that there are uses for the current behaviour. (Though I can't
recall having used it myself.)
But maybe for Python 4?
_______________________________________________
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/M4GFWNYKQUEYFWOS64VDPF5V5DZ7G4QJ/
Code of Conduct: http://python.org/psf/codeofconduct/