我已经了解到,可以在Python中向现有对象(即,不在类定义中)添加方法。
我明白这样做并不总是好的。但你怎么能做到这一点呢?
我已经了解到,可以在Python中向现有对象(即,不在类定义中)添加方法。
我明白这样做并不总是好的。但你怎么能做到这一点呢?
当前回答
这个问题早在几年前就提出了,但嘿,有一种简单的方法可以使用decorator模拟函数与类实例的绑定:
def binder (function, instance):
copy_of_function = type (function) (function.func_code, {})
copy_of_function.__bind_to__ = instance
def bound_function (*args, **kwargs):
return copy_of_function (copy_of_function.__bind_to__, *args, **kwargs)
return bound_function
class SupaClass (object):
def __init__ (self):
self.supaAttribute = 42
def new_method (self):
print self.supaAttribute
supaInstance = SupaClass ()
supaInstance.supMethod = binder (new_method, supaInstance)
otherInstance = SupaClass ()
otherInstance.supaAttribute = 72
otherInstance.supMethod = binder (new_method, otherInstance)
otherInstance.supMethod ()
supaInstance.supMethod ()
在那里,当您将函数和实例传递给绑定器装饰器时,它将创建一个新函数,其代码对象与第一个相同。然后,类的给定实例存储在新创建的函数的属性中。装饰器返回一个(第三个)函数,自动调用复制的函数,将实例作为第一个参数。最后,您将得到一个函数,模拟它与类实例的绑定。保持原始函数不变。
其他回答
from types import MethodType
def method(self):
print 'hi!'
setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )
使用此选项,可以使用self指针
这实际上是对“杰森·普拉特”答案的补充
虽然Jasons的答案是有效的,但它只在想要向类中添加函数时有效。当我试图从.py源代码文件重新加载一个已经存在的方法时,它对我来说并不起作用。
我花了很长时间才找到解决方法,但技巧似乎很简单。。。1.从源代码文件导入代码2.强制重新加载3.rd使用types.FunctionType(…)将导入和绑定的方法转换为函数您还可以传递当前的全局变量,因为重新加载的方法将位于不同的命名空间中4.现在你可以按照“杰森·普拉特”的建议继续使用类型.MethodType(…)
例子:
# this class resides inside ReloadCodeDemo.py
class A:
def bar( self ):
print "bar1"
def reloadCode(self, methodName):
''' use this function to reload any function of class A'''
import types
import ReloadCodeDemo as ReloadMod # import the code as module
reload (ReloadMod) # force a reload of the module
myM = getattr(ReloadMod.A,methodName) #get reloaded Method
myTempFunc = types.FunctionType(# convert the method to a simple function
myM.im_func.func_code, #the methods code
globals(), # globals to use
argdefs=myM.im_func.func_defaults # default values for variables if any
)
myNewM = types.MethodType(myTempFunc,self,self.__class__) #convert the function to a method
setattr(self,methodName,myNewM) # add the method to the function
if __name__ == '__main__':
a = A()
a.bar()
# now change your code and save the file
a.reloadCode('bar') # reloads the file
a.bar() # now executes the reloaded code
除了其他人所说的,我发现__repr_和__str__方法不能在对象级别上进行猴痘,因为repr()和str()使用类方法,而不是本地绑定的对象方法:
# Instance monkeypatch
[ins] In [55]: x.__str__ = show.__get__(x)
[ins] In [56]: x
Out[56]: <__main__.X at 0x7fc207180c10>
[ins] In [57]: str(x)
Out[57]: '<__main__.X object at 0x7fc207180c10>'
[ins] In [58]: x.__str__()
Nice object!
# Class monkeypatch
[ins] In [62]: X.__str__ = lambda _: "From class"
[ins] In [63]: str(x)
Out[63]: 'From class'
至少有两种方法可以将方法附加到没有类型的实例。MethodType:
>>> class A:
... def m(self):
... print 'im m, invoked with: ', self
>>> a = A()
>>> a.m()
im m, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.m
<bound method A.m of <__main__.A instance at 0x973ec6c>>
>>>
>>> def foo(firstargument):
... print 'im foo, invoked with: ', firstargument
>>> foo
<function foo at 0x978548c>
1:
>>> a.foo = foo.__get__(a, A) # or foo.__get__(a, type(a))
>>> a.foo()
im foo, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.foo
<bound method A.foo of <__main__.A instance at 0x973ec6c>>
2:
>>> instancemethod = type(A.m)
>>> instancemethod
<type 'instancemethod'>
>>> a.foo2 = instancemethod(foo, a, type(a))
>>> a.foo2()
im foo, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.foo2
<bound method instance.foo of <__main__.A instance at 0x973ec6c>>
有用的链接:数据模型-调用描述符描述符操作指南-调用描述符
杰森·普拉特发布的内容是正确的。
>>> class Test(object):
... def a(self):
... pass
...
>>> def b(self):
... pass
...
>>> Test.b = b
>>> type(b)
<type 'function'>
>>> type(Test.a)
<type 'instancemethod'>
>>> type(Test.b)
<type 'instancemethod'>
如您所见,Python认为b()与a()没有任何不同。在Python中,所有方法都只是恰好是函数的变量。