how do I use the __metaclass__ variable to change the default base class?

Gonçalo Rodrigues op73418 at mail.telepac.pt
Mon Dec 2 08:10:02 EST 2002


On Sun, 1 Dec 2002 20:52:28 -0800, Adam Feuer <adamf at pobox.com> wrote:

>Python folks, 
>
>I have a piece of Python software made up of many classes that I would
>like to collect information about at runtime- specifically, what
>classes hold references to what other classes.
>
>I thought it would be possible to define my own class that subclasses
>object, and redefine the __setattr__ method on that class.  Then, when
>I wanted to collect the information I would use the __metaclass__
>global variable to tell Python at runtime that all my classes now
>derive from my new base class (that is, the default base class for all
>classes is now MyObject)...
>

First advice: read the descintro on the new features of new-style
classes before reading my reply down below.

>I haven't been able to get this to work. What's wrong?
>
>. . . .
>class MyObject(object):
>   def __setattr__(self, name, value):
>      print "in __setattr__"
>      self.__dict__[name] = value
>
>__metaclass__ = MyObject
>
>class TestClass1:
>   def __init__(self):
>      self.foo = "bar"
>
>if __name__ == "__main__":
>   t1 = TestClass1()
>. . . .
>
>When I execute this code, I get an exception:
>
>$ python MetaclassTest2.py
>Traceback (most recent call last):
>  File "MetaclassTest2.py", line 13, in ?
>    t1 = TestClass1()
>TypeError: 'MyObject' object is not callable
>

You want to change the bases of a class, not the class's class (the
metaclass) - two different things (once again: read the descintro
carefully). Presently you cannot do that directly, e.g.:

>>> class test(object):
... 	pass
... 
>>> test.__bases__
(<type 'object'>,)
>>> test.__bases__ = str
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
TypeError: readonly attribute

I believe work is being done on a patch by M. Hudson for 2.3 to allow
this.

Anyway, prolly you can work up a metaclass to catch the bases argument
to the type constructor, muck with it, and *then* call the type
constructor. I'll leave the details to you.


>However, this next bit of code works- it doesn't use the __metaclass__
>variable but instead subclasses object directly:
>
>. . . .
>class MyObject(object):
>   def __setattr__(self, name, value):
>      print "in __setattr__"
>      self.__dict__[name] = value
>
>class TestClass1(MyObject):
>   def __init__(self):
>      self.foo = "bar"
>
>if __name__ == "__main__":
>   t1 = TestClass1()
>. . . .
>
>When I execute this, I get the expected result:
>
>$ python MetaclassTest1.py
>in __setattr__
>
>Help!
>
>By the way, I'm using Python 2.2.2 on Debian Linux 2.2.
>
>cheers
>adam

HTH,
G. Rodrigues



More information about the Python-list mailing list