4 ms·
My solution would be to fix it and break backwards compatibility: Any default value is evaluated anew on each function call without the specified value. Then yo
by bjoli 5y ago
My solution would be to fix it and break backwards compatibility: Any default value is evaluated anew on each function call without the specified value. Then you CAN mutate it to your hearts desire without impacting subsequent invocations. If you want to keep hidden mutable state between function invocations you should use a closure.
def banana(parts = []):
pass
Calling that procedure without parts would mean parts would be bound to a NEW empty list, not the same old.
Every new pyhton programmer is bitten by this sooner or later. Most people seem to think it is stupid, and relying on it seems, to me, to go against the python mantra of "being explicit", where explicit would mean either using an instance variable in the case of OO or a closure.
- davidatbu 5y agoIndeed, when I asked for potential solutions, I thought it would be ... weird, to evaluate default args at call time, but it turns out that many other languages are like that[0], and the wierdness was my subjective perception shaped by my Python-heavy background. Regarding breaking backward compatibility in a future release, I'm not qualified to weigh in on the design decision of balancing between the disadvantages of breaking backward compatibility and the advantage of more intuitive semantics. [0] https://github.com/microsoft/pyright/discussions/2306#discussioncomment-1337016 https://github.com/microsoft/pyright/discussions/2306#discus...
- patrickthebold 5y agoOne useful case for the existing is to eagerly bind variables: Here's a stupid example. Notice in the first case printing i doesn't grab the value of i when the lambda is defined. The second case is likely what you want. >>> lambdas = [lambda : print(i) for i in range(2)] >>> for l in lambdas: ... l() ... 1 1 >>> lambdas = [lambda i=i: print(i) for i in range(2)] >>> for l in lambdas: ... l() ... 0 1
- bjoli 5y agoOh my, that's awful. Even in python there are better ways to close over a value :) I haven't written python in many years, but in the following example it is at least clear what is going on: def make_printer(n): def printer(): print(n) return printer [make_printer(i) for i in range(2)]