11

General Python Question

I'm importing a Python library (call it animals.py) with the following class structure:

class Animal(object): pass

class Rat(Animal): pass

class Bat(Animal): pass

class Cat(Animal): pass

...

I want to add a parent class (Pet) to each of the species classes (Rat, Bat, Cat, ...); however, I cannot change the actual source of the library I'm importing, so it has to be a run time change.

The following seems to work:

import animals

class Pet(object): pass

for klass in (animals.Rat, animals.Bat, animals.Cat, ...): 
    klass.__bases__ = (Pet,) + klass.__bases__

Is this the best way to inject a parent class into an inheritance tree in Python without making modification to the source definition of the class to be modified?

Motivating Circumstances

I'm trying to graft persistence onto the a large library that controls lab equipment. Messing with it is out of the question. I want to give ZODB's Persistent a try. I don't want to write the mixin/facade wrapper library because I'm dealing with 100+ classes and lots of imports in my application code that would need to be updated. I'm testing options by hacking on my entry point only: setting up the DB, patching as shown above (but pulling the species classes w/ introspection on the animals module instead of explicit listing) then closing out the DB as I exit.

Mea Culpa / Request

This is an intentionally general question. I'm interested in different approaches to injecting a parent and comments on the pros and cons of those approaches. I agree that this sort of runtime chicanery would make for really confusing code. If I settle on ZODB I'll do something explicit. For now, as a regular user of python, I'm curious about the general case.

4
  • 2
    Don't do this. If you really can't modify the imported module, you must be able to at least see it if you can actually write a new parent class, so can't you trivially reimplement them in your module? If not, make subclasses that use Pet as a mixin if at all possible -- class PetRat(Pet, Rat): pass. Almost certainly you shouldn't do this at runtime, there is another way. Commented Sep 13, 2011 at 20:48
  • @agf The library is supported by a third party. Copy/paste reimplementation wouldn't be a good long-term solution. I think a wrapper library creating the PetXats by mixing in Pet would be better; however, as I said in my edit it's largely an academic / python internals questions. Commented Sep 13, 2011 at 22:27
  • I think you've outlined "the way", other than actually reading in the library module, rewriting it with a regex, and compiling it. Commented Sep 13, 2011 at 22:36
  • @agf: How is class Blah(Mixin, Main): pass better than inserting the new parent dynamically? Commented Jan 3, 2012 at 23:20

2 Answers 2

3

Your method is pretty much how to do it dynamically. The real question is: What does this new parent class add? If you are trying to insert your own methods in a method chain that exists in the classes already there, and they were not written properly, you won't be able to; if you are adding original methods (e.g. an interface layer), then you could possibly just use functions instead.

I am one who embraces Python's dynamic nature, and would have no problem using the code you have presented. Make sure you have good unit tests in place (dynamic or not ;), and that modifying the inheritance tree actually lets you do what you need, and enjoy Python!

Sign up to request clarification or add additional context in comments.

1 Comment

This has turned out to be one of those temporary solutions that worked well. I honestly haven't checked out the ZODB internals to figure out what Persistent does so I'm not sure what I'm adding but this seems to work. I tend to agree that dynamic to get the job done is OK, dynamic for its own sake is a maintenance problem. This felt like it was right on the line.
0

You should try really hard not to do this. It is strange, and will likely end in tears.

As @agf mentions, you can use Pet as a mixin. If you tell us more about why you want to insert a parent class, we can help you find a nicer solution.

1 Comment

I agree that it's strange and unlikely to be a good long term solution. I updated w/ additional info.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.