[Python-3000] Metaclasses in Py3K

Phillip J. Eby pje at telecommunity.com
Sat Dec 16 23:45:31 CET 2006

At 12:38 PM 12/16/2006 -0800, Talin wrote:
>Phillip J. Eby wrote:
>>At 11:30 AM 12/16/2006 -0800, Talin wrote:
>>>The general idea is to have the metaclass create a mapping object which
>>>is used as the 'locals' dictionary for the suite following the class
>>>statement. There would be some special-named function of the metaclass,
>>>such as '__metadict__', which would construct a new mapping object. I
>>>haven't seen many alternative proposals to this.
>>There's mine, where you simply create mcls(name, bases, {}) and then map 
>>locals operations to get/set/delattr operations on the class.  This would 
>>presumably be done using a simple mapping proxy, but it would be a 
>>built-in type rather than the user having to implement their own mapping type.
>I'm not sure I entirely understand this. I did think about the idea of 
>defining special get/set methods on the class, but everything I came up 
>with was more complicated than just creating a special locals dict.

My proposal uses a special locals dict, but it's a single standard builtin 
one that looks like this:

     class Metadict:
         def __init__(self, cls):
             self.cls = cls
         def __getitem__(self, key):
             return getattr(self.cls, key)
         def __setitem__(self, key, value):
             setattr(self.cls, key, value)
         def __delitem__(self, key):
             delattr(self.cls, key)

so, the class creation process is:

     cls = mcls(name, bases, {})
     exec suite in Metadict(cls), globals()

The idea is to avoid creating some new special-purpose mechanism for this, 
when we already have an existing one that would work nicely, given a 
suitable Metadict implementation.  Any get/set/delitem operations on the 
metadict map directly to get/set/delattr operations on the metaclass instance.

>The main issue for me is that I think that its important to distinguish 
>between get/set operations that are done at class definition time, and 
>get/set operations that are done later, after the class is created.

Well, we could always treat the class as a context manager, and allow the 
metaclass to have __enter__/__exit__ methods.  e.g.:

     cls = mcls(name, bases, {})
     if hasattr(cls,'__enter__'):
         with cls:
             exec suite in Metadict(cls), globals()
         exec suite in Metadict(cls), globals()

Unfortunately, this just highlights the attribute ambiguity problem where a 
class's attributes may be either provided by a metaclass, or be intended 
for the class' instances.  A class could have an __enter__ because it's 
inheriting it from its base class.  So, I suppose you would really need to 
check whether mcls has __enter__, but even then, you won't *execute* that 
__enter__ in the with: block, because an inherited __enter__ can override it.

(It'd be really nice if there was a way to generally fix this ambiguity in 
Py3K, as it's a problem for any method that could be on either a class or 
an instance, but isn't implemented via a C-level slot.  But that's probably 
another thread altogether.)

More information about the Python-3000 mailing list