Dynamically modified instance methods of the Python class

  • 2020-05-27 06:12:46
  • OfStack

Dynamically modified instance methods of the Python class

I believe that many friends in the programming will want to modify 1 has been written the program behavior code, and the most common way is to override the parent class through subclasses 1 some not meet the requirements of the method. Take this example.


class Dog:
  def bark(self):
    print 'Woof!'
 
class Husky(Dog):
  def bark(self)
    print 'Howl!'

We can modify our own code in the above way, but how should we modify the third party code? Of course, we could write a subclass ourselves and call the instance object of the subclass to implement the modification, but that might introduce other series 1 issues. So we'll have to find a way to replace the original object methods with our own, which is the "patch" approach we'll cover in this article.

Patch the class

If we want to add or modify methods to an object, the easiest way is to patch the class. In combination with the above example, if we want to write a new howl method for our own Dog class, we can define a new howl function and add it to our class as shown in code 1 below:


def newbark(self):
  print 'Wrooof!'
 
def howl(self):
  print 'Howl!'
 
# Replace an existing method
Dog.bark = newbark
 
# Add a new method
Dog.howl = howl

Simple, right? But there are a few things we need to be aware of. First, all instances of the modified class have methods updated, so that the updated methods do not only exist in the newly created object, but all previously created objects will have the updated methods, unless the original methods are added rather than overwritten. Second, the method you modify or add should be bound to the object, so the first argument to the method should be the object being called (in this case, the class instance self).

Patch class instances

A single object can also be patched without affecting other instances of the class. But it's a little tricky! Let's look at the following example first.


def herd(self, sheep):
  self.run()
  self.bark()
  self.run()
 
border_collie = Dog()
border_collie.herd = herd

Then let's try calling the newly defined method:


border_collie.herd(sheep)
 
TypeError: herd() takes exactly 2 arguments (1 given)
The problem with the previous code is that the herd is not a bound method, just take a look at the following code:
 
print border_collie.herd
 
<function herd at 0xf9c5f0>

Error! The cause of the error is that the object being called is not passed to the function as the first argument. Of course we can pass in the arguments ourselves, but it doesn't work in this scenario of replacing class methods. The correct solution to this problem is to use the MethodType function in the type module. We can take a look at the following sample code:


import types
 
border_collie = Dog()
border_collie.herd = types.MethodType(herd, border_collie)
 
print border_collie.herd
<bound method ?.herd of <__main__.Dog instance at 0x23c9518>>
 
border_collie.herd(sheep)

Now that our method is tied to the instance, we're done!

conclusion

It is useful to replace or add methods in the run. For example, in unit tests, some functions that are responsible for communicating with external services need to be replaced to facilitate testing. This technique is not only common, but it is also important to keep your code maintainable until you finally decide to change it.

Thank you for reading, I hope to help you, thank you for your support of this site!


Related articles: