Author ethan.furman
Recipients ethan.furman
Date 2013-04-27.08:10:01
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1367050201.95.0.307419620832.issue17853@psf.upfronthosting.co.za>
In-reply-to
Content
In playing with metaclasses for the ongoing Enum saga, I tried having the metaclass insert an object into the custom dict (aka namespace) returned by __prepare__; this object has the same name as the to-be-created class.

An example:

class Season(Enum):
    SPRING = Season()
    SUMMER = Season()
    AUTUMN = Season()
    WINTER = Season()

When this executes as top level code it works beautifully.

However, if you have the exact same definition in a function, Bad Things happen:

---------------------------------------
--> def test():
...   class Season(Enum):
...     SPRING = Season()
... 
--> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test
  File "<stdin>", line 3, in Season
NameError: free variable 'Season' referenced before assignment in enclosing scope
---------------------------------------

So I tried creating a dummy variable to see if it would be worked around:

---------------------------------------
--> def test():
...   Season = None
...   class Season(Enum):
...     SPRING = Season()
... 
--> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in test
  File "<stdin>", line 4, in Season
TypeError: 'NoneType' object is not callable
---------------------------------------

Finally I inserted the object using a different name, and also printed 'locals()' just to see what was going on:

---------------------------------------
--> def test():
...   class Season(Enum):
...     print(locals())
...     SPRING = S()
... 
--> test()
{'S': <class 'aenum.Season'>, 'Season': <class 'aenum.Season'>, '__module__': '__main__', '__qualname__': 'test.<locals>.Season', '__locals__': {...}}
---------------------------------------

and an actual (albeit extremely ugly) work around:

---------------------------------------
>>> def test():
...   class Season(Enum):
...     Season = locals()['Season']
...     SPRING = Season()
...   print(Season)
... 
>>> test()
Season(SPRING=1)
---------------------------------------

It seems that the function namespace is seriously messing with the class namespace.
History
Date User Action Args
2013-04-27 08:10:01ethan.furmansetrecipients: + ethan.furman
2013-04-27 08:10:01ethan.furmansetmessageid: <1367050201.95.0.307419620832.issue17853@psf.upfronthosting.co.za>
2013-04-27 08:10:01ethan.furmanlinkissue17853 messages
2013-04-27 08:10:01ethan.furmancreate