[issue17853] Conflict between lexical scoping and name injection in __prepare__

Nick Coghlan report at bugs.python.org
Sun Apr 28 05:22:50 CEST 2013


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 <report at bugs.python.org>
<http://bugs.python.org/issue17853>
_______________________________________


More information about the Python-bugs-list mailing list