I've read that it is possible to add a method to an existing object (i.e., not in the class definition) in Python.
I understand that it's not always good to do so. But how might one do this?
original title: "python - Adding a Method to an Existing Object Instance"
I've read that it is possible to add a method to an existing object (i.e., not in the class definition) in Python.
I understand that it's not always good to do so. But how might one do this?
Pythonで既存のオブジェクト(つまり、クラス定義ではない)にメソッドを追加することが可能であることを読みました。私はそうすることが必ずしも良いとは限らないことを理解しています。しかし、これをどうやって行うのでしょうか? ...
これは翻訳後の要約です。完全な翻訳を表示する必要がある場合は、「翻訳」アイコンをクリックしてください。
In Python, there is a difference between functions and bound methods.
Bound methods have been "bound" (how descriptive) to an instance, and that instance will be passed as the first argument whenever the method is called.
Callables that are attributes of a class (as opposed to an instance) are still unbound, though, so you can modify the class definition whenever you want:
Previously defined instances are updated as well (as long as they haven't overridden the attribute themselves):
The problem comes when you want to attach a method to a single instance:
The function is not automatically bound when it's attached directly to an instance:
To bind it, we can use the MethodType function in the types module:
This time other instances of the class have not been affected:
More information can be found by reading about descriptors and metaclass programming.
Module new is deprecated since python 2.6 and removed in 3.0, use types
see http://docs.python.org/library/new.html
In the example below I've deliberately removed return value from
patch_me()
function. I think that giving return value may make one believe that patch returns a new object, which is not true - it modifies the incoming one. Probably this can facilitate a more disciplined use of monkeypatching.Preface - a note on compatibility: other answers may only work in Python 2 - this answer should work perfectly well in Python 2 and 3. If writing Python 3 only, you might leave out explicitly inheriting from
object
, but otherwise the code should remain the same.Yes, it is possible - But not recommended
I don't recommend this. This is a bad idea. Don't do it.
Here's a couple of reasons:
Thus, I suggest that you not do this unless you have a really good reason. It is far better to define the correct method in the class definition or less preferably to monkey-patch the class directly, like this:
Since it's instructive, however, I'm going to show you some ways of doing this.
How it can be done
Here's some setup code. We need a class definition. It could be imported, but it really doesn't matter.
Create an instance:
Create a method to add to it:
Method nought (0) - use the descriptor method,
__get__
Dotted lookups on functions call the
__get__
method of the function with the instance, binding the object to the method and thus creating a "bound method."and now:
Method one - types.MethodType
First, import types, from which we'll get the method constructor:
Now we add the method to the instance. To do this, we require the MethodType constructor from the
types
module (which we imported above).The argument signature for types.MethodType is
(function, instance, class)
:and usage:
Method two: lexical binding
First, we create a wrapper function that binds the method to the instance:
usage:
Method three: functools.partial
A partial function applies the first argument(s) to a function (and optionally keyword arguments), and can later be called with the remaining arguments (and overriding keyword arguments). Thus:
This makes sense when you consider that bound methods are partial functions of the instance.
Unbound function as an object attribute - why this doesn't work:
If we try to add the sample_method in the same way as we might add it to the class, it is unbound from the instance, and doesn't take the implicit self as the first argument.
We can make the unbound function work by explicitly passing the instance (or anything, since this method doesn't actually use the
self
argument variable), but it would not be consistent with the expected signature of other instances (if we're monkey-patching this instance):Conclusion
You now know several ways you could do this, but in all seriousness - don't do this.
I think that the above answers missed the key point.
Let's have a class with a method:
Now, let's play with it in ipython:
Ok, so m() somehow becomes an unbound method of A. But is it really like that?
It turns out that m() is just a function, reference to which is added to A class dictionary - there's no magic. Then why A.m gives us an unbound method? It's because the dot is not translated to a simple dictionary lookup. It's de facto a call of A.__class__.__getattribute__(A, 'm'):
Now, I'm not sure out of the top of my head why the last line is printed twice, but still it's clear what's going on there.
Now, what the default __getattribute__ does is that it checks if the attribute is a so-called descriptor or not, i.e. if it implements a special __get__ method. If it implements that method, then what is returned is the result of calling that __get__ method. Going back to the first version of our A class, this is what we have:
And because Python functions implement the descriptor protocol, if they are called on behalf of an object, they bind themselves to that object in their __get__ method.
Ok, so how to add a method to an existing object? Assuming you don't mind patching class, it's as simple as:
Then B.m "becomes" an unbound method, thanks to the descriptor magic.
And if you want to add a method just to a single object, then you have to emulate the machinery yourself, by using types.MethodType:
By the way:
In Python monkey patching generally works by overwriting a class or functions signature with your own. Below is an example from the Zope Wiki:
That code will overwrite/create a method called speak on the class. In Jeff Atwood's recent post on monkey patching. He shows an example in C# 3.0 which is the current language I use for work.
You can use lambda to bind a method to an instance:
Output:
There are at least two ways for attach a method to an instance without
types.MethodType
:1:
2:
Useful links:
Data model - invoking descriptors
Descriptor HowTo Guide - invoking descriptors
What you're looking for is
setattr
I believe. Use this to set an attribute on an object.Since this question asked for non-Python versions, here's JavaScript:
Consolidating Jason Pratt's and the community wiki answers, with a look at the results of different methods of binding:
Especially note how adding the binding function as a class method works, but the referencing scope is incorrect.
Personally, I prefer the external ADDMETHOD function route, as it allows me to dynamically assign new method names within an iterator as well.
This is actually an addon to the answer of "Jason Pratt"
Although Jasons answer works, it does only work if one wants to add a function to a class. It did not work for me when I tried to reload an already existing method from the .py source code file.
It took me for ages to find a workaround, but the trick seems simple... 1.st import the code from the source code file 2.nd force a reload 3.rd use types.FunctionType(...) to convert the imported and bound method to a function you can also pass on the current global variables, as the reloaded method would be in a different namespace 4.th now you can continue as suggested by "Jason Pratt" using the types.MethodType(...)
Example:
If it can be of any help, I recently released a Python library named Gorilla to make the process of monkey patching more convenient.
Using a function
needle()
to patch a module namedguineapig
goes as follows:But it also takes care of more interesting use cases as shown in the FAQ from the documentation.
The code is available on GitHub.
What Jason Pratt posted is correct.
As you can see, Python doesn't consider b() any different than a(). In Python all methods are just variables that happen to be functions.
This question was opened years ago, but hey, there's an easy way to simulate the binding of a function to a class instance using decorators:
There, when you pass the function and the instance to the binder decorator, it will create a new function, with the same code object as the first one. Then, the given instance of the class is stored in an attribute of the newly created function. The decorator return a (third) function calling automatically the copied function, giving the instance as the first parameter.
In conclusion you get a function simulating it's binding to the class instance. Letting the original function unchanged.
I find it strange that nobody mentioned that all of the methods listed above creates a cycle reference between the added method and the instance, causing the object to be persistent till garbage collection. There was an old trick adding a descriptor by extending the class of the object:
With this, you can use the self pointer