problem in using metaclasses to inspect Python code
Greg Chapman
glc at well.com
Fri Dec 13 10:40:34 EST 2002
On 12 Dec 2002 11:36:37 -0800, mis6 at pitt.edu (Michele Simionato) wrote:
>If I write
>
>class Meta(type):
> def __init__(cls,name,bases,dict):
> print "%s called me!" % name
>
>class C(object):
> __metaclass__=Meta
>
>then the output of this program is what you expect:
>
>C called me!
>
>However, if I write
>
>class D(object):
> pass
>
>D.__metaclass__=Meta
>
>I DON'T obtain what I expect, i.e. "D called me!": the metaclass
>Meta is not automatically called. How do I invoke Meta explicitly ?
Ignoring metaclasses for the moment, suppose we had:
class C(object):
pass
class D(C):
pass
c = C()
Now suppose you want to change the __class__ of c from C to D. You can do this
in Python:
c.__class__ = D
but you certainly wouldn't expect c's __init__ method to be called again (at
least I hope you ouldn't).
The case is just the same for metaclasses:
class D(object):
pass
The above class statement creates D as an instance of the metaclass 'type.' The
metaclass is determined by looking at the 'object' class and discovering that
its __class__ is 'type'. When you include a __metaclass__ attr in a class
declaration, you override this to say you want to use the given metaclass as the
__class__ of the class which is being created (the __metaclass__ attr has no
effect once the new class is created). Just as when you create an instance of
an object you call the object's class (i.e., c = C()), to create an instance of
a class, Python calls the class's class (the metaclass). And just as when you
call a class to create an instance, the call goes through the class's __new__
and __init__ methods, when you call a metaclass to create a class, the call goes
through the metaclass's __new__ and __init__ methods.
class Meta(type):
def sayHi(cls):
print 'hi from Meta'
print 'class instance is', cls.__name__
The above class statement creates a subtype of the 'type' metaclass.
D.__class__ = Meta
D.sayHi() #prints 'hi from Meta\nclass instance is D'
The above changes the metaclass of the type instance D from type to Meta
Anyway, just as for instances, you would not expect D's __init__ (as defined in
its metaclass) to be called again when you change its __class__.
I hope I'm not belaboring this too much, but you could do away with the class
statement entirely if you wanted. E.g.:
>>> D = type('D', (object,), {})
>>> def sayHi(cls):
... print 'hi from Meta'
... print 'class instance is', cls.__name__
...
>>> Meta = type('Meta', (type,), {'sayHi': sayHi})
>>> D.__class__ = Meta
>>> D.sayHi()
hi from Meta
class instance is D
>>> E = Meta('E', (), {})
>>> E.sayHi()
hi from Meta
class instance is E
>>> e = E()
>>> e.__class__
<class '__main__.E'>
>>> e.__class__.__class__
<class '__main__.Meta'>
---
Greg Chapman
More information about the Python-list
mailing list