In Python 3 there's the nonlocal keyword to deal with the scoping thing.
The default arguments thing is worse than a lot of the stuff Python 3 corrected.
I don't see how nonlocal could fix this. Could you explain?
More specifically, given a better 'default arguments thing', how would you interpret:
x = [2]
def f(x=x*5):
x.append(4)
With the earlier conversion it's: x = [2]
def f(x=DefaultArg):
if x is DefaultArg:
x = x*5
x.append(4)
This isn't going to work because the x inside of f() is different than the outside x, and you'll get the error message I mentioned.If you add a nonlocal, as in:
x = [2]
def f(x=DefaultArg):
nonlocal x
if x is DefaultArg:
x = x*5
x.append(4)
then you'll get "SyntaxError: name 'x' is parameter and nonlocal".What other solution are you thinking of?
Ah I see. Yeah nonlocal can't fix that.
Why not just memoize the result of the slow function?
I think by your use of "just memoize" that I didn't explain myself well enough. I don't mean to focus on the slow aspect, nor even the function aspect. It could be
def foo(default_arg = [0]*(256*256)):
...
and still get the same namespace issues.Memoization is not always going to be an available solution. For example, it may be that slow_f() returns a stateless object, so can be reused, while slow_f(x) returns something stateful. You can think of my examples as either using default arguments as a single element memo, or using a module variable for the same. Both premised on the idea that the developer knows enough to make the right decision.
What breaks is something like:
Under the shorthand gets turned into: This is fine, since everyone would know that the shorthand means to not put slow code there. Instead, people will start writing it as: Of course, then what happens with: ? Under expansion it becomes: This violates Python's scoping rules, because _foo_arg is now being used in local scope instead of global scope. Eg: Which means you now need a new scoping rule, just to handle default parameters without making things more confusing.It also turns what was a simple O(1) offset into a precomputed list into a globals() lookup for many cases.