On 25.05.20 03:03, Rob Cliffe via Python-ideas wrote:
On 24/05/2020 21:03, Dominik Vilsmeier wrote:
That's very clever, but if you compare it with the status quo: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) # [], {}
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.
Actually it was intended to use type annotations a la PEP 585 (using builtin types directly) and hence not requiring explicit specification of the factory:
@supply_defaults
def bar(x: list = None, y: dict = None):
pass
This also has the advantage that the types are visible in the
function signature. Sure this works only in a limited number of
cases, but the case of mutable defaults seems to be quite
prominent, and this solves it at little cost.
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:={}):
What about using `~` instead of `:=`. As a horizontal symbol it has some similarity to `=` and usually "~" denotes proportionality which also allows to make a connection to the use case. For proportionality "x ~ y" means there's a non-zero constant "k" such that "x = k*y" and in the case of defaults it would mean, there's a non-trivial step such that `x = step(y)` (where `step=eval` roughly).
def bar(x=1, y~[], z ~ {}):
It looks better with spaces around "~" but that's probably a matter of being used to it.
A disadvantage is that `~` is already a unary operator, so one
could do this: `def foo(x~~y)`. But how often does this occur
anyway?