[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()
else:
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