Monkey-patch Python class

PythonMonkeypatching

Python Problem Overview


I've got a class, located in a separate module, which I can't change.

from module import MyClass

class ReplaceClass(object)
  ...

MyClass = ReplaceClass

This doesn't change MyClass anywhere else but this file. However if I'll add a method like this

def bar():
   print 123

MyClass.foo = bar

this will work and foo method will be available everywhere else.

How do I replace the class completely?

Python Solutions


Solution 1 - Python

import module
class ReplaceClass(object):
    ....
module.MyClass = ReplaceClass

Solution 2 - Python

Avoid the from ... import (horrid;-) way to get barenames when what you need most often are qualified names. Once you do things the right Pythonic way:

import module

class ReplaceClass(object): ...

module.MyClass = ReplaceClass

This way, you're monkeypatching the module object, which is what you need and will work when that module is used for others. With the from ... form, you just don't have the module object (one way to look at the glaring defect of most people's use of from ...) and so you're obviously worse off;-);

The one way in which I recommend using the from statement is to import a module from within a package:

from some.package.here import amodule

so you're still getting the module object and will use qualified names for all the names in that module.

Solution 3 - Python

I am but an egg . . . . Perhaps it is obvious to not-newbies, but I needed the from some.package.module import module idiom.

I had to modify one method of GenerallyHelpfulClass. This failed:

import some.package.module

class SpeciallyHelpfulClass(some.package.module.GenerallyHelpfulClass): 
    def general_method(self):...

some.package.module.GenerallyHelpfulClass = SpeciallyHelpfulClass

The code ran, but didn't use the behaviors overloaded onto SpeciallyHelpfulClass.

This worked:

from some.package import module

class SpeciallyHelpfulClass(module.GenerallyHelpfulClass): 
    def general_method(self):...

module.GenerallyHelpfulClass = SpeciallyHelpfulClass

I speculate that the from ... import idiom 'gets the module', as Alex wrote, as it will be picked up by other modules in the package. Speculating further, the longer dotted reference seems to bring the module into the namespace with the import by long dotted reference, but doesn't change the module used by other namespaces. Thus changes to the import module would only appear in the name space where they were made. It's as if there were two copies of the same module, each available under slightly different references.

Solution 4 - Python

import some_module_name

class MyClass(object): 
     ... #copy/paste source class and update/add your logic

some_module_name.MyClass = MyClass

Its preferable not to change the name of class while replacing, because somehow someone may have referenced them using getattr - which will result in fail like below

getattr(some_module_name, 'MyClass') --> which will fail if you have replaced MyClass by ReplaceClass !

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZooKeeperView Question on Stackoverflow
Solution 1 - PythonGlenn MaynardView Answer on Stackoverflow
Solution 2 - PythonAlex MartelliView Answer on Stackoverflow
Solution 3 - PythonchernevikView Answer on Stackoverflow
Solution 4 - PythonshahjapanView Answer on Stackoverflow