Author ethan.furman
Recipients daniel.urban, ethan.furman, mark.dickinson
Date 2013-04-27.21:17:58
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <517C4088.1060801@stoneleaf.us>
In-reply-to <1367096486.18.0.183635163843.issue17853@psf.upfronthosting.co.za>
Content
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.
History
Date User Action Args
2013-04-27 21:17:59ethan.furmansetrecipients: + mark.dickinson, daniel.urban
2013-04-27 21:17:59ethan.furmanlinkissue17853 messages
2013-04-27 21:17:58ethan.furmancreate