1

I have a library with one parent and a dozen of children:

# mylib1.py:
#
class Foo(object):
  def __init__(self, a):
    self.a = a


class FooChild(Foo):
  def __init__(self, a, b):
    super(FooChild, self).__init__(a)
    self.b = b

# more children here...

Now I want to extend that library with a simple (but a bit spesific, for use in another approach) method. So I would like to change parent class and use it's children.

# mylib2.py:
#
import mylib1

def fooMethod(self):
  print 'a={}, b={}'.format(self.a, self.b)

setattr(mylib1.Foo, 'fooMethod', fooMethod)

And now I can use it like this:

# way ONE:
import mylib2

fc = mylib2.mylib1.FooChild(3, 4)
fc.fooMethod()

or like this:

# way TWO:
# order doesn't matter here:
import mylib1
import mylib2

fc = mylib1.FooChild(3, 4)

fc.fooMethod()

So, my questions are:

  1. Is this good thing?
  2. How this should be done in a better way?
brownian
  • 435
  • 3
  • 13
  • what are you trying to achieve? Why do you need to add a method dynamically? – Pynchia Jun 12 '15 at 09:03
  • @Pynchia, I'm asking how to do this better. So I have to use `mylib1.Foo` and *all* its subclasses and I need to have `fooMethod` in all those [sub]classes. And I don't want to subclass everything. – brownian Jun 12 '15 at 09:46

2 Answers2

4

A common approach is to use mixin

If you want, you could add dynamically How do I dynamically add mixins as base classes without getting MRO errors?.

Community
  • 1
  • 1
Ali SAID OMAR
  • 6,404
  • 8
  • 39
  • 56
0

There is a general rule in programming, that you should avoid dependence on global state. Which in other words means that your globals should be if possible constant. Classes are (mostly) globals.

Your approach is called monkey patching. And if you don't have a really really good reason to explain it, you should avoid it. This is because monkey patching violates the above rule.

Imagine you have two separate modules and both of them use this approach. One of them sets Foo.fooMethod to some method. The other - to another. Then you somehow switch control between these modules. The result would be, that it would be hard to determine what fooMethod is used where. This means hard to debug problems.

There are people (e.g. Brandon Craig-Rhodes), who believe that patching is bad even in tests.

What I would suggest is to use some attribute that you would set when instantiating instances of your Foo() class (and its children), that would control the behaviour of your fooMethod. Then the behaviour of this method would depend on how you instantiated the object, not on global state.

zefciu
  • 1,967
  • 2
  • 17
  • 39
  • Should I create `class Moo` with appropriate `mooMethod` and subclass every `mylib1.*` from `Moo`? Like this: `class FooMoo(Foo, Moo)` then `class SubFooMoo(SubFoo, Moo)` --- and the same for all classes from `mylib1`? – brownian Jun 12 '15 at 09:56
  • 1
    I think this question should go to 'said omar' because he suggested the mixin approach. My suggestion was to create a generic fooMethod that could word differently depending on some attribute. But not knowing, what is your purpose it is hard to say what is the correct approach. You should avoid monkeypatching however. – zefciu Jun 12 '15 at 10:09