There are a number of way to add a new method to an existing instance dynamically in Python without needing to change its class and without affecting other existing objects.
A pre-defined class called Cat
Instantiate two objects called Tuxedo and Calico respectively.class Cat(object):
def __init__(self, name):
self.name = '[inner] ' + name
tuxedo = Cat('Tuxedo')
calico = Cat('Calico')
# normal functions
def meow(self):
print('%s is meowing.' % self.name)
def sleep(self):
print('%s is sleeping.' % self.name)
def catch(self, stuff):
print('%s is catching %s' % (self.name, stuff))
Use functools.partial
We can see there is no defined function in the class. Let's add a meow() function to an instance. Use functools.partial to pre-bind the function and store it in the object dictionary so it can be accessed like a method.from functools import partial
tuxedo.meow = partial(meow, tuxedo) # pre-bound and stored in the instance
tuxedo.meow() # access like a normal method
>> [inner] Tuxedo is meowing.
Use a helper function in a more elegant way.
def bind(obj, func):
'Bind a function and store it in an object'
setattr(obj, func.__name__, partial(func, obj))
bind(calico, meow)
calico.meow()
>> [inner] Calico is meowing.
Use types
The argument signature for types.MethodType is (function, instance, class):import types
def bind(obj, func):
setattr(obj, func.__name__, types.MethodType(func, obj))
bind(tuxedo, sleep)
tuxedo.sleep()
>> [inner] Tuxedo is sleeping.
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."calico.catch = catch.__get__(calico)
calico.catch('a mouse')
>> [inner] Calico catches a mouse
Use lexical binding
def bind(instance, method):
def binding_scope_fn(*args, **kwargs):
return method(instance, *args, **kwargs)
return binding_scope_fn
tuxedo.catch = bind(tuxedo, catch)
tuxedo.catch('two mice')
>> [inner] Tuxedo catches two mice
Unbound function as an object attribute - why this doesn't work:
tuxedo.catch = catch
tuxedo.catch('three mice')
>> tuxedo.catch('three mice')
TypeError: catch() missing 1 required positional argument: 'stuff'
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):
tuxedo.catch(tuxedo, 'three mice')
>> [inner] Tuxedo catches three mice
Use namedtuple
from collections import namedtuple
Cat = namedtuple('Cat', ['age', 'weight'])
cat = Cat(age=5, weight=13)
print('My cat is %d years old, Her weight is %d pounds.' % (cat.age, cat.weight))
>> My cat is 5 years old, Her weight is 13 pounds.
cat2 = Cat() # error
>> TypeError: __new__() missing 2 required positional arguments: 'age' and 'weight'
Use property
tabby = Cat('Tabby')
tabby.kittens = 0
print('Tabby has %d newborn kittens so far.' % tabby.kittens)
>> Tabby has 0 newborn kittens so far.
Cat.give_birth = property(lambda self: self.kittens + 1)
tabby.kittens = tabby.give_birth
print('Tabby gives birth to %d kitten(s).' % tabby.kittens)
>> Tabby gives birth to 1 kitten(s).
A property is actually a simple implementation of a thing called a descriptor. It's an object that provides custom handling for a given attribute, on a given class. Kinda like a way to factor a huge if tree out of __getattribute__.When I ask for tabby.give_birth in the example above, Python sees that the give_birth defined on the class implements the descriptor protocol—which just means it's an object with a __get__, __set__, or __delete__ method. The descriptor claims responsibility for handling that attribute, so Python calls Cat.give_birth.__get__(tabby, Cat), and the return value is passed back to you as the value of the attribute. In the case of property, each of these methods just calls the fget, fset, or fdel you passed to the property constructor.
For more information about descriptors
Concerns of binding a new method
According to Aaron Hall's answer in Stackoverflow. Here's a couple of reasons:- You'll add a bound object to every instance you do this to. If you do this a lot, you'll probably waste a lot of memory. Bound methods are typically only created for the short duration of their call, and they then cease to exist when automatically garbage collected. If you do this manually, you'll have a name binding referencing the bound method - which will prevent its garbage collection on usage.
- Object instances of a given type generally have its methods on all objects of that type. If you add methods elsewhere, some instances will have those methods and others will not. Programmers will not expect this, and you risk violating the rule of least surprise.
- Since there are other really good reasons not to do this, you'll additionally give yourself a poor reputation if you do it.
Thus, he suggests 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.
References
- Any elegant way to add a method to an existing object in python
- Adding a method to an existing object instance
- How to add property to a class dynamically
Good content. You write beautiful things.
回覆刪除mrbahis
vbet
korsan taksi
vbet
sportsbet
sportsbet
hacklink
taksi
hacklink
Success Write content success. Thanks.
回覆刪除canlı slot siteleri
betpark
betmatik
kıbrıs bahis siteleri
deneme bonusu
canlı poker siteleri
betturkey
dijital kartvizit
回覆刪除referans kimliği nedir
binance referans kodu
referans kimliği nedir
bitcoin nasıl alınır
resimli magnet
G834FH
hatay
回覆刪除kars
mardin
samsun
urfa
267W
urfa
回覆刪除antakya
ısparta
aydın
diyarbakır
ZVD