Message187953
Just to clarify, the problem here isn't to do with referencing the class name in particular, it's referencing *any* lexically scoped name from the class body, when a metaclass wants to inject that as variable name in the class namespace. Here's a case where it silently looks up the wrong value:
>>> class Meta(type): pass
...
>>> def f():
... outer = "lexically scoped"
... class inner(metaclass=Meta):
... print(outer)
...
>>> f()
lexically scoped
>>> class Meta(type):
... def __prepare__(*args):
... return dict(outer="from metaclass")
...
>>> f()
lexically scoped
That second one *should* say "from metaclass", but it doesn't because the LOAD_DEREF completely ignores the local namespace. You can get the same exception noted above by moving the assignment after the inner class definition:
>>> def g():
... class inner(metaclass=Meta):
... print(outer)
... outer = "This causes an exception"
...
>>> g()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in g
File "<stdin>", line 3, in inner
NameError: free variable 'outer' referenced before assignment in enclosing scope
We simply missed the fact that PEP 3115 and the __prepare__ method mean that using LOAD_DEREF to resolve lexically scoped names in a nested class is now wrong. Instead, we need a new opcode that first tries the class namespace and only if that fails does it fall back to looking it up in the lexically scoped cell reference.
(I changed the affected versions, as even though this *is* a bug in all current Python 3 versions, there's no way we're going to change the behaviour of name resolution in a maintenance release) |
|
Date |
User |
Action |
Args |
2013-04-28 03:22:50 | ncoghlan | set | recipients:
+ ncoghlan, mark.dickinson, daniel.urban, ethan.furman |
2013-04-28 03:22:50 | ncoghlan | set | messageid: <1367119370.19.0.295121882093.issue17853@psf.upfronthosting.co.za> |
2013-04-28 03:22:50 | ncoghlan | link | issue17853 messages |
2013-04-28 03:22:49 | ncoghlan | create | |
|