Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: replacing a function within a class of a module

Tags:

I'm trying to replace a function defined within a class in order to modify its function (as in inner workings) without changing the actual code. I've never done this before, and, hence, am having some problems while replacing it.

Changing the code will have me accessing the package within my Python library which is not much of an option.

For example, if the module was called testMOD,

class testMOD(object):     def testFunc(self, variable):         var = variable         self.something = var + 12 

Then I would import testMOD, define a class (mytest = testMOD()), and access the defined function within the class, testFunc, and change it to already defined function.

For instance,

from somemodule import testMOD mytest = testMOD()  def alternativeFunc(self, variable):     var = variable     self.something = var + 1.2  # A problem here mytest.testFunc = alternativeFunc 

As you can see, if I just manually overwrite(?) the function in the class with my defined function it won't work properly.

It doesn't give any syntax errors, however, the problem is that the replaced function thinks that the 'self' is another variable for the function and says that it requires another argument for the 'variable' variable (I guess that wasn't a good name).

I want to make the replacing function to be exactly the same thing as the replaced function, but with additional code or some minor modifications. However, the 'self' is pretty much not working as it should be in a class.

Would there be a way to properly implement a defined function to replace a function of an imported class?

like image 875
Cody Chung Avatar asked May 30 '18 07:05

Cody Chung


People also ask

What is __ module __?

The __module__ property is intended for retrieving the module where the function was defined, either to read the source code or sometimes to re-import it in a script.


1 Answers

I suggest 4 solutions, from the worst to the best (IMHO), but of course it also depends on your specific constraints:

  1. Replace the instance method (1): I use the fact that functions are descriptors in Python, so that I can use the __get__ method on AlternativeFunc to get it as a method of the instance mytest and overwrite the testFunc method of the instance mytest (without overwriting the class method):

    class testMOD(object):     def testFunc(self, variable):         var = variable         self.something = var + 12         print('Original:', self.something)  def alternativeFunc1(self, variable):     var = variable     self.something = var + 1.2     print('Alternative1:', self.something)  mytest1 = testMOD() mytest1.testFunc(10)   # Original: 22  mytest1.testFunc = alternativeFunc1.__get__(mytest1, testMOD) mytest1.testFunc(10)   # Alternative1: 11.2 mytestX = testMOD() mytestX.testFunc(10)   # Original: 22 
  2. Replace the instance method (2): This time, I use types.MethodType which is a bit more readable than the first solution:

    import types  class testMOD(object):     def testFunc(self, variable):         var = variable         self.something = var + 12         print('Original:', self.something)  def alternativeFunc1(self, variable):     var = variable     self.something = var + 1.2     print('Alternative1:', self.something)  mytest1 = testMOD() mytest1.testFunc(10)   # Original: 22  funcType = types.MethodType mytest1.testFunc = funcType(alternativeFunc1, mytest1) mytest1.testFunc(10)   # Alternative1: 11.2 mytestX = testMOD() mytestX.testFunc(10)   # Original: 22 
  3. Perform a monkey patching of the class method. Differently from the first method, it changes the behavior of any instance of the class:

    class testMOD(object):     def testFunc(self, variable):         var = variable         self.something = var + 12         print('Original:', self.something)  def alternativeFunc2(self, variable):     var = variable     self.something = var + 1.2     print('Alternative2:', self.something)  mytest2 = testMOD() mytest2.testFunc(10)   # Original: 22  testMOD.testFunc = alternativeFunc2 mytest2.testFunc(10)   # Alternative2: 11.2 mytestX = testMOD() mytestX.testFunc(10)   # Alternative2: 11.2 
  4. Create a class inherited from testMOD to override the method:

    class testMODNew(testMOD):      def testFunc(self, variable):          var = variable          self.something = var + 1.2          print('Alternative3:', self.something)  mytest3 = testMODNew() mytest3.testFunc(10) # Alternative3: 11.2 
like image 81
Laurent H. Avatar answered Sep 19 '22 13:09

Laurent H.