runtime inheritance (e.g. __new__, __metaclass__)

Steven Bethard steven.bethard at gmail.com
Wed Jul 28 21:24:04 CEST 2004


"H Jansen" <h.jansen at fel.tno.nl> wrote in message news:<mailman.872.1091016384.5135.python-list at python.org>...
> What I want to achieve at runtime is this:
> 
> g1 = Good(Base1)  # a Good object with base class Base1
> g2 = Good(Base2)  # a Good object with base class Base2

Peter's solution is clean (and the way I'd go) as long as you don't
mind Good being a function, not a class.  If you need Good to be a
class, you could probably get what you want by changing the __bases__
attribute:

>>> class Base1:
... 	def __init__(self):
... 		print "Base1"
... 		
>>> class Base2:
... 	def __init__(self):
... 		print "Base2"
... 		
>>> class Good:
... 	pass
... 
>>> Good.__bases__ = (Base1, )
>>> Good()
Base1
<__main__.Good instance at 0x00E6D738>
>>> Good.__bases__ = (Base2, )
>>> Good()
Base2
<__main__.Good instance at 0x00E6DC38>

Note that once you've changed the base classes of the Good class,
you'll have to change them back if you want the original behavior
again.

Or if you actually need different Good classes, you could try
something like:

>>> class Base1(object):
... 	def __init__(self):
... 		print "Base1"
... 
>>> class Base2(object):
... 	def __init__(self):
... 		print "Base2"
... 
>>> class Good(object):
... 	pass
... 
>>> Good1 = type.__new__(type, "Good1", (Base1,), dict(Good.__dict__))
>>> Good1()
Base1
<__main__.Good1 object at 0x00E664F0>
>>> Good2 = type.__new__(type, "Good2", (Base2,), dict(Good.__dict__))
>>> Good2()
Base2
<__main__.Good2 object at 0x00E66450>

Note that type.__new__ requires a dict (not a dictproxy like the
__dict__ attribute), so I've copied the Good.__dict__ attribute
instead of having both classes reference the same one.  This means
that if you have a class variable in Good (and therefore in Good1 and
Good2), if you modify it in Good1, it will not be modified in Good2,
e.g.:

>>> Good1 = type.__new__(type, "Good1", (Base1,), dict(Good.__dict__))
>>> Good2 = type.__new__(type, "Good2", (Base2,), dict(Good.__dict__))
>>> Good1.x = 2
>>> Good1.x
2
>>> Good2.x
1

This may or may not be desirable.

This technique does seem to transfer any methods successfully:

>>> class Good(object):
... 	def f(self, x):
... 		print (self.__class__, x)
... 	
>>> Good1 = type.__new__(type, "Good1", (Base1,), dict(Good.__dict__))
>>> Good2 = type.__new__(type, "Good2", (Base2,), dict(Good.__dict__))
>>> Good1().f(1)
Base1
(<class '__main__.Good1'>, 1)
>>> Good2().f(2)
Base2
(<class '__main__.Good2'>, 2)

Steve



More information about the Python-list mailing list