python中为类和实例动态增加方法

>>> def func(a,b):

...     print a,b

...  

>>> class Foo(object):

...     pass

...     

>>> foo = Foo()

>>> foo.func(4)

Traceback (most recent call last):

  File "<input>", line 1, in <module>

AttributeError: 'Foo' object has no attribute 'func'


>>> Foo.func = func #类动态增加方法一:直接赋值

>>> Foo.func

<unbound method Foo.func>

>>> 

>>> foo.func(4)

<__main__.Foo object at 0x3f79db0> 4


>>> foo.func

<bound method Foo.func of <__main__.Foo object at 0x3f79db0>>


>>> foo.func2=func # 实例这样做是不行的,得到的只是一个可调用的属性

>>> foo.func2

<function func at 0x3f66df0>

>>> foo.func2(1,2)

1 2

>>> foo.func2(4)

Traceback (most recent call last):

  File "<input>", line 1, in <module>

TypeError: func() takes exactly 2 arguments (1 given)


>>> import new

>>> foo.func3 = new.instancemethod(func,foo,Foo)#实例动态增加方法一:

>>> foo.func3

<bound method Foo.func of <__main__.Foo object at 0x3f79db0>>

>>> foo.func3(4)

<__main__.Foo object at 0x3f79db0> 4

>>> dir(Foo)

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'func']

>>> dir(foo)

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'func', 'func2', 'func3']

>>> 


http://wendal.net/351.html

Python: 为对象动态添加函数,且函数定义来自一个str

Python,通常情况下,你只能为对象添加一个已经写好的方法

需求:传入一个str类型的变量,其值是一个完整的合法的Python函数定义,然后为一个对象添加这个函数:

method_str = u'''

def say(self, name)

    print 'My nameis', name

'''

class MyClass:


    def __init__(self):

        pass


    def extends(self, method_name, method_str):

        #完成这个方法...


obj =MyClass();

obj.extends('say', method_str)

obj.say('wendal')#打印出My name is wendal

想了不少路子,PythonQQ群里面也得到不少灵感,最后顺利实现:

    def extends(sefl, method_name, method_str):

        #_method = None

        exec method_str + '''\n_method = %s''' % method_name

        self.__dict__[method_name]= new.instancemethod(_method,self, None)

简单解释一下: method_strexec,改变为:

method_str = u'''

def say(self, name)

    print 'My nameis', name

_method = abc

然后, exec执行后,_method变量就赋值为say函数接下来,就是Python的自省机制了,通过new模块,生成特定对象(本例中是self)的实例方法最后,为特定对象添加say这个函数

,这例子,就足以体现出Python在这方面的扩展性 1. method_str是一个字符串,可以动态创建,例如用户输出,模板生成 2. 方法的名字可以通过字符串分割等方法获取到

昨晚完成这个实现之后,足足兴奋了一个小时,哈哈 – 2行代码就搞定!!


http://blog.lzhaohao.info/archive/python-dynamic-instance-bound-method-access-to-private-method/

python中实例动态绑定的方法访问私有方法

Posted in python On 2011-05-24 09:46:59 , tagged withpython.

python有一个编译好的模块,需要增加一个方法。由于不想修改源代码再编译,所以使用动态绑定方法来给实例增加方法。

第一印象,想到使用如下方法:

1

2

3

4

5

deffoo(self):

    print self.name

 

a =A()

a.foo =foo

1

2

3

4

>>> a.foo()

Traceback (most recent call last):

  File"<stdin>", line 1, in<module>

TypeError: foo() takes exactly 1argument (0given)

结果是无法访问实例的变量。 比较新绑定的方法与原有的实例方法,发现原有的实例方法是bound method。只有bound method才能访问实例的变量。

要动态为实例绑定方法,可以使用new模块(http://docs.python.org/library/new.html)(文档中说new模块已经过期,推荐使用types模块。但我看types的文档,想不明白如何取代new模块)

1

2

import new

a.foo =new.instancemethod(foo, a, A)

问题又来了,新加的方法里有调用实例的私有函数(以双下划线开头),报了如下错误:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

class A():

    def__private(self):

        print "private"

 

    defpublic(self):

        self.__private()

 

deffoo(self):

    self.__private()

 

a =A()

import new

a.foo =new.instancemethod(foo, a, A)

a.foo()

1

2

3

4

5

6

Traceback (most recent call last):

  File"E:tmptest.py", line 14, in<module>

    a.foo()

  File"E:tmptest.py", line 9,infoo

    self.__private()

AttributeError: A instance has no attribute '__private'

通过观察原有方法和动态绑定方法的字节码,发现LOAD_ATTR有差别。原有方法的LOAD_ATTR“_A__private”,动态绑定的方法的LOAD_ATTR“__private”

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

class A():

    def__private(self):

        print "private"

 

    defpublic(self):

        self.__private()

 

deffoo(self):

    self.__private()

 

a =A()

import dis

dis.dis(a.public)

a.public()

 

import new

a.foo =new.instancemethod(foo, a, A)

dis.dis(a.foo)

a.foo()

1

2

3

4

5

6

7

8

9

10

11

12

13

  6          0 LOAD_FAST               0 (self)

              3LOAD_ATTR                0(_A__private) # a.public

              6CALL_FUNCTION            0

              9 POP_TOP

             10LOAD_CONST               0(None)

             13 RETURN_VALUE

private

  9          0 LOAD_FAST               0 (self)

              3LOAD_ATTR                0(__private) # a.foo

              6CALL_FUNCTION            0

              9 POP_TOP

             10LOAD_CONST               0(None)

             13 RETURN_VALUE

这里的原因是python会对private方法进行名字粉碎(name mangling) 。因此修改foo方法里面的调用为self._A__private(),通过。但这样修改后,方法对于不同的class会不通用,有待研究更好的方法

http://outofmemory.cn/code-snippet/2856/python-dongtai-modify-class-method-execution-logical

python动态修改类方法的执行逻辑

下面的代码演示如何给已经定义好的python类添加方法,替代已有方法:

from __future__ import nested_scopes

import new


def enhance_method(klass, method_name, replacement):

    '替代已有的方法'

    method = getattr(klass, method_name)

    setattr(klass, method_name, new.instancemethod(

        lambda *args, **kwds: replacement(method, *args, **kwds),None, klass))


def method_logger(old_method, self, *args, **kwds):

    '给方法添加调用执行日志'

    print '*** calling: %s%s, kwds=%s' % (old_method.__name__, args, kwds)

    return_value = old_method(self, *args, **kwds)# call the original method

    print'*** %s returns: %s' % (old_method.__name__, `return_value`)

    return return_value


def demo():

    class Deli:

        def order_cheese(self, cheese_type):

            print'Sorry, we are completely out of %s' % cheese_type


    d = Deli()

    d.order_cheese('Gouda')


    enhance_method(Deli, 'order_cheese', method_logger)

    d.order_cheese('Cheddar')

当需要修改第三方python包的某个类的某个方法时,这种修改方式非常有用。

-----------setattr方法-------------


>>> def func3(self, a):

...     print self.__a

...     

>>> def func4(self,b):

...     print self._b

... 

>>> def func5(self,c):

...     print self.c

...


>>> class Foo(object):

...     def __init__(self):

...         self.__a = 3

...         self._b=4

...         self.c=5

...     def printme(self):

...         print self.__a, self._b, self.c

...         

>>> foo = Foo()

>>> foo.printme()

3 4 5

>>> foo.funcc=new.instancemethod(func5,foo,Foo)

>>> foo.funcc(5)

5

>>> foo.funcb=new.instancemethod(func4,foo,Foo)

>>> foo.funcb(4)

4

>>> foo.funca=new.instancemethod(func3,foo,Foo)

>>> foo.funca(3)

Traceback (most recent call last):

  File "<input>", line 1, in <module>

  File "<input>", line 2, in func3

AttributeError: 'Foo' object has no attribute '__a'

>>> foo.funcx=new.instancemethod(func3,foo,None)

>>> foo.funcx(0)

Traceback (most recent call last):

  File "<input>", line 1, in <module>

  File "<input>", line 2, in func3

AttributeError: 'Foo' object has no attribute '__a'

>>> setattr(foo,'funcy',func3.__get__(foo,Foo))

>>> foo.funcy

<bound method Foo.func3 of <__main__.Foo object at 0x3f81730>>

>>> foo.funcy(3)

Traceback (most recent call last):

  File "<input>", line 1, in <module>

  File "<input>", line 2, in func3

AttributeError: 'Foo' object has no attribute '__a'

>>> 

>>> def func6(self,a):

...     print self._Foo__a

...     

>>> foo.funcz=new.instancemethod(func6,foo,None)

>>> foo.funcz(6)

3

>>> 

---------------目前为止动态加的方法都不能访问实例的私有变量,除了加类名的方式


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值