
Jan Kaliszewski wrote:
Steven D'Aprano dixit (2011-06-16, 10:46):
Making locals unrebindable is a change of semantics that is far beyond anything I've been discussed here. This will be a big enough change without overloading it with changes that will be even more controversial!
That variant (#1) would be simply shortcut for a closure application -- nothing really new.
def factory(n): """Today's Python example.""" closuring = 'foo' def func(m): s = min(n, m) * closuring # here you also cannot rebind 'closuring' because is has # been referenced above
The error occurs BEFORE the rebinding attempt. You get UnboundLocalError when you attempt to execute min(n, m), not when rebinding the closure variable. This is a side-effect of the compiler's rule "if you see an assignment to a variable, make it a local", that is all. You can rebind closuring if you tell the compiler that it isn't a local variable:
def factory(n): ... closuring = 'foo' ... def func(m): ... nonlocal closuring ... s = min(n, m)*closuring ... closuring = 'spam' ... return s + closuring ... return func ... f = factory(10) f(3) 'foofoofoospam'
In that regard, closure variables are no different from globals. You wouldn't say that global are unrebindable because of this:
def f(): ... print(x) ... x = 1 ... f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f UnboundLocalError: local variable 'x' referenced before assignment
The situation is very similar.
Introducing magic syntax that is recognised by the compiler but otherwise is not usable as a function is completely unacceptable.
Because of?... And it would not be more 'magic' than any other language syntax construct -- def, class, decorating with their @, *, ** arguments etc. The fact that such a new syntax would be similar to something already known and well settled (decorator function application syntax) would be rather an andantage than a drawback.
But the problem is that it is deceptively similar: it only *seems* similar, while the differences are profound. super() is the only magic function I know of in Python, and that change was controversial, hard to implement, and fragile. super() is special cased by the compiler and works in ways that no other function can do. Hence it is magic. I can't imagine that Guido will agree to a second example, at least not without a blindingly obvious benefit. You can't reason about super()'s behaviour like any other function. Things which should work if super() were non-magical break, such as aliasing: my_super = super # Just another name for the same function. class MyList(list): def __init__(self, *args): my_super().__init__(*args) self.attr = None
MyList([]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in __init__ SystemError: super(): __class__ cell not found
And wrapping: _saved_super = super def super(*args, **kwargs): print(args, kwargs) return _saved_super(*args, **kwargs) class MyList(list): def __init__(self, *args): super().__init__(*args) self.attr = None
MyList([]) () {} Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in __init__ File "<stdin>", line 3, in super SystemError: super(): no arguments
Only the exact incantation of built-in super() inside a method of a class works. As I said: magic. (Although you can supply all the arguments for super manually, which is tricky to get right but non-magic.) You are proposing that inject should also be magic: only the exact incantation @inject(...) directly above a function will work. We won't be able to wrap inject in another function, or alias it, or use it without the @ syntax. inject() isn't really a decorator, although it superficially looks like one. It's actually a compiler directive. If you want to propose #pragma for Python, do so, but don't call it a decorator! Most importantly, we won't be able to apply it to functions that already exist: list_of_functions = [spam, ham, cheese] # defined elsewhere decorator = inject(a=1) decorated = [decorator(f) for f in list_of_functions] will fail. I consider this completely unacceptable. -- Steven