Swapping superclass from a module
Arnaud Delobelle
arnodel at googlemail.com
Sat May 16 15:17:30 EDT 2009
"Emanuele D'Arrigo" <manu3d at gmail.com> writes:
> Hi everybody,
>
> let's assume I have a module with loads of classes inheriting from one
> class, from the same module, i.e.:
>
> ## myFile.py
> class SuperClass(object)
> class SubClass1(SuperClass)
> class SubClass2(SuperClass)
> class SubClass3(SuperClass)
>
> In a separate file I also have:
>
> ## myOtherFile.py
> class NewSuperClass(object)
>
> Now, let's also assume that myFile.py cannot be changed or it's
> impractical to do so. Is there a way to replace the SuperClass at
> runtime, so that when I instantiate one of the subclasses
> NewSuperClass is used instead of the original SuperClass provided by
> the first module module?
>
> That was the generic case. Would the solution change much if
> NewSuperClass was actually inheriting from SuperClass, effectively
> wedging itself between the SuperClass and the SubClasses?
>
Here is an attempt to do this. Imagine there is a module 'modfoo.py'
like this:
--------------------------------------------------
class Base(object):
def bar(self):
print 'Base.bar'
class A(Base):
def bar(self):
Base.bar(self)
print 'A.bar'
class B(Base):
def bar(self):
super(B, self).bar()
print 'B.bar'
--------------------------------------------------
The following script will patch the module so that all subclasses of
Base in module modfoo have their new superclass changed. I called it
'patchfoo.py'.
--------------------------------------------------
import modfoo
# This is the new base
class Wedge(modfoo.Base):
def bar(self):
super(Wedge, self).bar()
print 'Wedge.bar'
# Insert Wedge into each subclass of modfoo.Base
for subclass in modfoo.Base.__subclasses__():
if subclass.__module__ != 'modfoo': continue
attrs = dict(item for item in subclass.__dict__.items()
if item[0][:2] != '__')
name = subclass.__name__
setattr(modfoo, name, type(name, (Wedge,), attrs))
# Replace modfoo.Base with Wedge
modfoo.Base = Wedge
# Tests
a = modfoo.A()
b = modfoo.B()
for obj in 'a' ,'b':
call = '%s.bar()' % (obj,)
print '-'*5, call
exec call
--------------------------------------------------
Now let's try it:
marigold:junk arno$ python patchfoo.py
----- a.bar()
Base.bar
Wedge.bar
A.bar
----- b.bar()
Base.bar
Wedge.bar
B.bar
Of course, there are plenty of ways this could break.
--
Arnaud
More information about the Python-list
mailing list