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
I think that the above answers missed the key point.
Let's have a class with a method:
class A(object):
def m(self):
pass
Now, let's play with it in ipython:
In [2]: A.m
Out[2]:
Ok, so m() somehow becomes an unbound method of A. But is it really like that?
In [5]: A.__dict__['m']
Out[5]:
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'):
In [11]: class MetaA(type):
....: def __getattribute__(self, attr_name):
....: print str(self), '-', attr_name
In [12]: class A(object):
....: __metaclass__ = MetaA
In [23]: A.m
- m
- 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:
In [28]: A.__dict__['m'].__get__(None, A)
Out[28]:
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:
B.m = m
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:
b.m = types.MethodType(m, b)
By the way:
In [2]: A.m
Out[2]:
In [59]: type(A.m)
Out[59]:
In [60]: type(b.m)
Out[60]:
In [61]: types.MethodType
Out[61]: