Python 向现有对象实例添加方法
我已经读到,可以在Python中向现有对象(即,不在类定义中)添加方法Python 向现有对象实例添加方法,python,oop,methods,monkeypatching,Python,Oop,Methods,Monkeypatching,我已经读到,可以在Python中向现有对象(即,不在类定义中)添加方法 我知道这样做并不总是好的。但是如何做到这一点呢?在Python中,monkeypatching通常通过用自己的签名覆盖类或函数的签名来工作。以下是一个来自以下方面的示例: 此代码将覆盖/创建类中名为peak的方法。在Jeff Atwood的文章中,他展示了C#3.0中的一个示例,这是我当前工作中使用的语言。在Python中,函数和绑定方法之间存在差异 >>> def foo(): ... print
我知道这样做并不总是好的。但是如何做到这一点呢?在Python中,monkeypatching通常通过用自己的签名覆盖类或函数的签名来工作。以下是一个来自以下方面的示例:
此代码将覆盖/创建类中名为
peak
的方法。在Jeff Atwood的文章中,他展示了C#3.0中的一个示例,这是我当前工作中使用的语言。在Python中,函数和绑定方法之间存在差异
>>> def foo():
... print "foo"
...
>>> class A:
... def bar( self ):
... print "bar"
...
>>> a = A()
>>> foo
<function foo at 0x00A98D70>
>>> a.bar
<bound method A.bar of <__main__.A instance at 0x00A9BC88>>
>>>
如果要将方法附加到单个实例,则会出现问题:
>>> def barFighters( self ):
... print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: barFighters() takes exactly 1 argument (0 given)
>>> a.barFighters
<function barFighters at 0x00A98EF0>
def run(self):
print self._instanceString
class A(object):
def __init__(self):
self._instanceString = "This is instance string"
a = A()
a.run = lambda: run(a)
a.run()
foo = Foo()
def bind(instance, method):
def binding_scope_fn(*args, **kwargs):
return method(instance, *args, **kwargs)
return binding_scope_fn
>>> foo.sample_method(foo, 1, 2)
3
def barFighters(自):
... 打印“酒吧战士”
...
>>>a.酒吧斗士=酒吧斗士
>>>a.酒吧斗士()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:barFighters()正好接受1个参数(给定0)
直接连接到实例时,函数不会自动绑定:
>>> def barFighters( self ):
... print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: barFighters() takes exactly 1 argument (0 given)
>>> a.barFighters
<function barFighters at 0x00A98EF0>
def run(self):
print self._instanceString
class A(object):
def __init__(self):
self._instanceString = "This is instance string"
a = A()
a.run = lambda: run(a)
a.run()
foo = Foo()
def bind(instance, method):
def binding_scope_fn(*args, **kwargs):
return method(instance, *args, **kwargs)
return binding_scope_fn
>>> foo.sample_method(foo, 1, 2)
3
>a.barFighters
要绑定它,我们可以使用:
导入类型
>>>a.barFighters=types.MethodType(barFighters,a)
>>>酒吧斗士
>>>a.酒吧斗士()
酒吧斗士
这一次,该类的其他实例没有受到影响:
>>> a2.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'barFighters'
>a2.barFighters()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:实例没有属性“barFighters”
通过阅读和可以找到更多信息。我相信您正在寻找的是
setattr
。
使用此选项可以在对象上设置属性
>>> def printme(s): print repr(s)
>>> class A: pass
>>> setattr(A,'printme',printme)
>>> a = A()
>>> a.printme() # s becomes the implicit 'self' variable
< __ main __ . A instance at 0xABCDEFG>
>def printme(s):打印报告
>>>甲级:及格
>>>setattr(A,'printme',printme)
>>>a=a()
>>>a.printme()#s成为隐式“self”变量
<主。0xABCDEFG>
杰森·普拉特发布的内容是正确的
>>> 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'>
>类测试(对象):
... def a(自我):
... 通过
...
>>>def b(自我):
... 通过
...
>>>测试b=b
>>>类型(b)
>>>类型(试验a)
>>>类型(测试b)
如您所见,Python并不认为B()与A.()有任何不同。在Python中,所有方法都只是碰巧是函数的变量
Modulenew自python 2.6以来已被弃用,并在3.0中被删除,请使用类型 看 在下面的示例中,我特意删除了patch\u me()
函数的返回值。
我认为,给出返回值可能会让人相信patch返回了一个新对象,这是不正确的——它修改了传入的对象。这可能有助于更严格地使用monkeypatching
import types
class A(object):#but seems to work for old style objects too
pass
def patch_me(target):
def method(target,x):
print "x=",x
print "called from", target
target.method = types.MethodType(method,target)
#add more if needed
a = A()
print a
#out: <__main__.A object at 0x2b73ac88bfd0>
patch_me(a) #patch instance
a.method(5)
#out: x= 5
#out: called from <__main__.A object at 0x2b73ac88bfd0>
patch_me(A)
A.method(6) #can patch class too
#out: x= 6
#out: called from <class '__main__.A'>
导入类型
A类(对象):#但似乎也适用于旧式对象
通过
def修补程序(目标):
def方法(目标,x):
打印“x=”,x
打印“调用自”,目标
target.method=types.MethodType(方法,目标)
#如果需要,添加更多
a=a()
打印
#输出:
补丁(a)#补丁实例
a、 方法(5)
#输出:x=5
#外出:从
修补程序(A)
方法(6)#也可以修补类
#输出:x=6
#外出:从
我认为上述答案没有抓住关键点
让我们创建一个具有方法的类:
class A(object):
def m(self):
pass
现在,让我们在ipython中玩它:
In [2]: A.m
Out[2]: <unbound method A.m>
然后,由于描述符的魔力,B.m“成为”一个未绑定的方法
如果只想将方法添加到单个对象,则必须使用types.MethodType自己模拟机器
b.m = types.MethodType(m, b)
顺便说一下:
In [2]: A.m
Out[2]: <unbound method A.m>
In [59]: type(A.m)
Out[59]: <type 'instancemethod'>
In [60]: type(b.m)
Out[60]: <type 'instancemethod'>
In [61]: types.MethodType
Out[61]: <type 'instancemethod'>
[2]中的:上午
出[2]:
In[59]:类型(A.m)
出[59]:
In[60]:类型(b.m)
出[60]:
在[61]中:types.MethodType
出[61]:
整合Jason Pratt和社区wiki的答案,查看不同绑定方法的结果:
特别要注意,作为类方法添加绑定函数是如何工作的,但是引用范围是不正确的
#!/usr/bin/python -u
import types
import inspect
## dynamically adding methods to a unique instance of a class
# get a list of a class's method type attributes
def listattr(c):
for m in [(n, v) for n, v in inspect.getmembers(c, inspect.ismethod) if isinstance(v,types.MethodType)]:
print m[0], m[1]
# externally bind a function as a method of an instance of a class
def ADDMETHOD(c, method, name):
c.__dict__[name] = types.MethodType(method, c)
class C():
r = 10 # class attribute variable to test bound scope
def __init__(self):
pass
#internally bind a function as a method of self's class -- note that this one has issues!
def addmethod(self, method, name):
self.__dict__[name] = types.MethodType( method, self.__class__ )
# predfined function to compare with
def f0(self, x):
print 'f0\tx = %d\tr = %d' % ( x, self.r)
a = C() # created before modified instnace
b = C() # modified instnace
def f1(self, x): # bind internally
print 'f1\tx = %d\tr = %d' % ( x, self.r )
def f2( self, x): # add to class instance's .__dict__ as method type
print 'f2\tx = %d\tr = %d' % ( x, self.r )
def f3( self, x): # assign to class as method type
print 'f3\tx = %d\tr = %d' % ( x, self.r )
def f4( self, x): # add to class instance's .__dict__ using a general function
print 'f4\tx = %d\tr = %d' % ( x, self.r )
b.addmethod(f1, 'f1')
b.__dict__['f2'] = types.MethodType( f2, b)
b.f3 = types.MethodType( f3, b)
ADDMETHOD(b, f4, 'f4')
b.f0(0) # OUT: f0 x = 0 r = 10
b.f1(1) # OUT: f1 x = 1 r = 10
b.f2(2) # OUT: f2 x = 2 r = 10
b.f3(3) # OUT: f3 x = 3 r = 10
b.f4(4) # OUT: f4 x = 4 r = 10
k = 2
print 'changing b.r from {0} to {1}'.format(b.r, k)
b.r = k
print 'new b.r = {0}'.format(b.r)
b.f0(0) # OUT: f0 x = 0 r = 2
b.f1(1) # OUT: f1 x = 1 r = 10 !!!!!!!!!
b.f2(2) # OUT: f2 x = 2 r = 2
b.f3(3) # OUT: f3 x = 3 r = 2
b.f4(4) # OUT: f4 x = 4 r = 2
c = C() # created after modifying instance
# let's have a look at each instance's method type attributes
print '\nattributes of a:'
listattr(a)
# OUT:
# attributes of a:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FD88>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FD88>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FD88>>
print '\nattributes of b:'
listattr(b)
# OUT:
# attributes of b:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FE08>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FE08>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FE08>>
# f1 <bound method ?.f1 of <class __main__.C at 0x000000000237AB28>>
# f2 <bound method ?.f2 of <__main__.C instance at 0x000000000230FE08>>
# f3 <bound method ?.f3 of <__main__.C instance at 0x000000000230FE08>>
# f4 <bound method ?.f4 of <__main__.C instance at 0x000000000230FE08>>
print '\nattributes of c:'
listattr(c)
# OUT:
# attributes of c:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002313108>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002313108>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002313108>>
#/usr/bin/python-u
导入类型
进口检验
##向类的唯一实例动态添加方法
#获取类的方法类型属性的列表
def listattr(c):
对于m in[(n,v)对于n,v in inspect.getmembers(c,inspect.ismethod),如果是instance(v,types.MethodType)]:
打印m[0],m[1]
#将函数作为类实例的方法进行外部绑定
def ADDMETHOD(c,方法,名称):
c、 _uuudict_uuuu[name]=types.MethodType(方法,c)
C类():
r=10#类属性变量到测试范围
定义初始化(自):
通过
#将函数作为self类的方法进行内部绑定——请注意,这个函数有问题!
def addmethod(self、method、name):
self.\uuuu dict\uuuuu[name]=类型.MethodType(方法,self.\uuuuu类)
#要与之比较的预定义函数
def f0(自身,x):
打印“f0\tx=%d\tr=%d%”(x,self.r)
a=C()#在修改仪表之前创建
b=C()#修改后的仪表
def f1(自身,x):#内部绑定
打印“f1\tx=%d\tr=%d%”(x,self.r)
def f2(self,x):#添加到类实例的.uu dict_uu作为方法类型
打印'f2\tx=%d\tr=%d'(x,self.r)
def f3(self,x):#将类指定为方法类型
打印“f3\tx=%d\tr=%d%”(x,self.r)
def f4(self,x):#使用常规函数添加到类实例。uu dict_u_u
打印“f4\tx=%d\tr=%d%”(x,self.r)
b、 addmethod(f1,'f1')
b、 _uuudict_uuu['f2']=types.MethodType(f2,b)
b、 f3=类型。方法类型(f3,b)
ADDMETHOD(b,f4,'f4')
b、 f0(0)#OUT:f0x=0r=10
b、 f1(1)#输出:f1 x=1 r=10
b、 f2(2)#输出:f2 x=2 r=10
b、 f3(3)#输出:f3 x=3 r=10
b、 f4(4)#输出:F4X=4R=10
k=2
打印“将b.r从{0}更改为{1}”。格式(b.r,k)
b、 r=k
打印“新b.r={0}”。格式(b.r)
b、 f0(0)#OUT:f0x=0r=2
b、 f1(1)#出局:f1 x=1 r=10!!!!!!!!!
b、 f2(2)#输出:f2 x=2 r=2
b、 f3(3)#输出:f3 x=3 r=2
b、 f4(4)#输出:F4X=4R=2
c=c()#修改实例后创建
#让我们看看每个实例的方法类型属性
打印“\n a:的属性”
listattr(a)
#输出:
#阿特里布
>>> 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>
>>> 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>>
>>> 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>>
import gorilla
import guineapig
@gorilla.patch(guineapig)
def needle():
print("awesome")
def run(self):
print self._instanceString
class A(object):
def __init__(self):
self._instanceString = "This is instance string"
a = A()
a.run = lambda: run(a)
a.run()
This is instance string
Foo.sample_method = sample_method
class Foo(object):
'''An empty class to demonstrate adding a method to an instance'''
foo = Foo()
def sample_method(self, bar, baz):
print(bar + baz)
foo.sample_method = sample_method.__get__(foo)
>>> foo.sample_method(1,2)
3
import types
foo.sample_method = types.MethodType(sample_method, foo, Foo)
>>> foo.sample_method(1,2)
3
def bind(instance, method):
def binding_scope_fn(*args, **kwargs):
return method(instance, *args, **kwargs)
return binding_scope_fn
>>> foo.sample_method = bind(foo, sample_method)
>>> foo.sample_method(1,2)
3
>>> from functools import partial
>>> foo.sample_method = partial(sample_method, foo)
>>> foo.sample_method(1,2)
3
>>> foo.sample_method = sample_method
>>> foo.sample_method(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sample_method() takes exactly 3 arguments (2 given)
>>> foo.sample_method(foo, 1, 2)
3
# 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
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 ()
def addmethod(obj, name, func):
klass = obj.__class__
subclass = type(klass.__name__, (klass,), {})
setattr(subclass, name, func)
obj.__class__ = subclass
from types import MethodType
def method(self):
print 'hi!'
setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )
# 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'