>>> 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>
import types
class A(object):#but seems to work for old style objects toopass
def patch_me(target):def method(target,x):print "x=",xprint "called from", targettarget.method = types.MethodType(method,target)#add more if needed
a = A()print a#out: <__main__.A object at 0x2b73ac88bfd0>patch_me(a) #patch instancea.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'>
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<class '__main__.A'> - m<class '__main__.A'> - m
#!/usr/bin/python -uimport typesimport inspect
## dynamically adding methods to a unique instance of a class
# get a list of a class's method type attributesdef 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 classdef 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 withdef f0(self, x):print 'f0\tx = %d\tr = %d' % ( x, self.r)
a = C() # created before modified instnaceb = C() # modified instnace
def f1(self, x): # bind internallyprint 'f1\tx = %d\tr = %d' % ( x, self.r )def f2( self, x): # add to class instance's .__dict__ as method typeprint 'f2\tx = %d\tr = %d' % ( x, self.r )def f3( self, x): # assign to class as method typeprint 'f3\tx = %d\tr = %d' % ( x, self.r )def f4( self, x): # add to class instance's .__dict__ using a general functionprint '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 = 10b.f1(1) # OUT: f1 x = 1 r = 10b.f2(2) # OUT: f2 x = 2 r = 10b.f3(3) # OUT: f3 x = 3 r = 10b.f4(4) # OUT: f4 x = 4 r = 10
k = 2print 'changing b.r from {0} to {1}'.format(b.r, k)b.r = kprint 'new b.r = {0}'.format(b.r)
b.f0(0) # OUT: f0 x = 0 r = 2b.f1(1) # OUT: f1 x = 1 r = 10 !!!!!!!!!b.f2(2) # OUT: f2 x = 2 r = 2b.f3(3) # OUT: f3 x = 3 r = 2b.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 attributesprint '\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>>
就个人而言,我更喜欢外部ADDMETHOD函数路由,因为它允许我在迭代器中动态分配新方法名称。
def y(self, x):passd = C()for i in range(1,5):ADDMETHOD(d, y, 'f%d' % i)print '\nattributes of d:'listattr(d)# OUT:# attributes of d:# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002303508>># addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002303508>># f0 <bound method C.f0 of <__main__.C instance at 0x0000000002303508>># f1 <bound method ?.y of <__main__.C instance at 0x0000000002303508>># f2 <bound method ?.y of <__main__.C instance at 0x0000000002303508>># f3 <bound method ?.y of <__main__.C instance at 0x0000000002303508>># f4 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
>>> 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>>
# this class resides inside ReloadCodeDemo.pyclass A:def bar( self ):print "bar1"
def reloadCode(self, methodName):''' use this function to reload any function of class A'''import typesimport ReloadCodeDemo as ReloadMod # import the code as modulereload (ReloadMod) # force a reload of the modulemyM = getattr(ReloadMod.A,methodName) #get reloaded MethodmyTempFunc = types.FunctionType(# convert the method to a simple functionmyM.im_func.func_code, #the methods codeglobals(), # globals to useargdefs=myM.im_func.func_defaults # default values for variables if any)myNewM = types.MethodType(myTempFunc,self,self.__class__) #convert the function to a methodsetattr(self,methodName,myNewM) # add the method to the function
if __name__ == '__main__':a = A()a.bar()# now change your code and save the filea.reloadCode('bar') # reloads the filea.bar() # now executes the reloaded code
# Instance monkeypatch[ins] In [55]: x.__str__ = show.__get__(x)
[ins] In [56]: xOut[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'
class UnderWater:def __init__(self):self.net = 'underwater'
marine = UnderWater() # Instantiate the class
# Recover the class from the instance and add attributes to it.class SubMarine(marine.__class__):def __init__(self):super().__init__()self.sound = 'Sonar'
print(SubMarine, SubMarine.__name__, SubMarine().net, SubMarine().sound)
# Output# (__main__.SubMarine,'SubMarine', 'underwater', 'Sonar')