Nick Coghlan added the comment: 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) ---------- nosy: +ncoghlan title: class construction name resolution broken in functions -> Conflict between lexical scoping and name injection in __prepare__ versions: +Python 3.4 -Python 3.2, Python 3.3 _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue17853> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com