[issue17853] class construction name resolution broken in functions

Ethan Furman report at bugs.python.org
Sat Apr 27 23:17:59 CEST 2013


Ethan Furman added the comment:

On 04/27/2013 02:01 PM, Mark Dickinson wrote:
>
> Mark Dickinson added the comment:
>
> Isn't this just a consequence of Python's usual name-lookup rules?  In this code:
>
>      def test():
>          class Season(Enum):
>              SPRING = Season()
>
> the class definition in 'test' amounts to a local assignment to the name 'Season'.  So the occurrence of 'Season' in the class definition is bound to that function local (at bytecode level, it's looked up using LOAD_DEREF instead of LOAD_NAME).

The key point is that class construction should take place in its own namespace (it has its own locals(), after all), 
only looking to enclosing name spaces if it can't find the name in its locals() (which it won't know until it tries). 
Granted, this was never a problem before __prepare__ was available, but now that it is we need to have the name space 
look-up rules applied appropriately, and not have the enclosing function strong-arm its own values into the class namespace.

> I find it difficult to see how one could 'fix' this without significant changes to the way that Python does name resolution.

I don't know if this helps, but here's the dis for three different runs:

--> def test1():
...   class WeekDay(Enum):
...      MONDAY = WeekDay(1)
...
--> dis.dis(test1)
   2           0 LOAD_BUILD_CLASS
               1 LOAD_CLOSURE             0 (WeekDay)
               4 BUILD_TUPLE              1
               7 LOAD_CONST               1 (<code object WeekDay at 0x7f60264c6608, file "<stdin>", line 2>)
              10 MAKE_CLOSURE             0
              13 LOAD_CONST               2 ('WeekDay')
              16 LOAD_GLOBAL              0 (Enum)
              19 CALL_FUNCTION            3
              22 STORE_DEREF              0 (WeekDay)
              25 LOAD_CONST               0 (None)
              28 RETURN_VALUE

--> def test2():
...   class WeekDay(Enum):
...     MONDAY = enum(1)
...
--> dis.dis(test2)
   2           0 LOAD_BUILD_CLASS
               1 LOAD_CONST               1 (<code object WeekDay at 0x7f602490b7a0, file "<stdin>", line 2>)
               4 MAKE_FUNCTION            0
               7 LOAD_CONST               2 ('WeekDay')
              10 LOAD_GLOBAL              0 (Enum)
              13 CALL_FUNCTION            3
              16 STORE_FAST               0 (WeekDay)
              19 LOAD_CONST               0 (None)
              22 RETURN_VALUE

--> def test3():
...   class WeekDay(Enum):
...     WeekDay = locals()['WeekDay']
...     MONDAY = WeekDay(1)
...
--> dis.dis(test3)
   2           0 LOAD_BUILD_CLASS
               1 LOAD_CONST               1 (<code object WeekDay at 0x7f602490ee88, file "<stdin>", line 2>)
               4 MAKE_FUNCTION            0
               7 LOAD_CONST               2 ('WeekDay')
              10 LOAD_GLOBAL              0 (Enum)
              13 CALL_FUNCTION            3
              16 STORE_FAST               0 (WeekDay)
              19 LOAD_CONST               0 (None)
              22 RETURN_VALUE

test1's dis should look more like test3's.  Also, I find it interesting that test2's dis is exactly the same as test3's.

----------

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue17853>
_______________________________________


More information about the Python-bugs-list mailing list