Back to home

在Python中给类或者实例动态添加方法

原文:http://www.ianlewis.org/en/dynamically-adding-method-classes-or-class-instanc

在Python中你有时希望动态的给某个类型或者实例(对象)添加一个方法。下面的代码中,以最显然的方法实现了一个,但是会得到一个警告

class MyObj(object):
    def __init__(self, val):
        self.val = val


def new_method(self, value):
    return self.val + value


obj = MyObj(3)
obj.method = new_method

但是你不能使用 self 引用,让我们试一下

>>> obj.method(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: new_method() takes exactly 2 arguments (1 given)

new_method方法作为一个带有两个参数的属性添加到了一个类型的实例中。那么我们添加的方法如何使用self参数?答案是使用types模块的MethodType

>>> from types import MethodType
>>> obj.method = MethodType(new_method, obj, MyObj)
>>> obj.method(5)
8

好,现在可以使用self了。MethodType类型实际上会将方法绑定一个实例,并且创造一个"绑定方法".

>>> obj.method
<bound method MyObj.new_method of <__main__.MyObj object at 0xb75c928c>>

这里的method方法只是绑定了一个单独的实例。如果我们创建另外一个MyObj类型实例,它不会拥有这个方法。

>>> obj2 = MyObj(2)
>>> obj2.method(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyObj' object has no attribute 'method

所以在我们创建的新实例中并不包含这个方法。如果我们需要这样呢?我们可以添加一个 “unbound method” 给这个类。

>>> MyObj.method = MethodType(new_method, None, MyObj)
>>> MyObj.method
<unbound method MyObj.new_method>
>>> obj2 = MyObj(2)
>>> obj2.method(5)
7

所以我们能够创建任意数量的包含我们新方法的MyObj类型实例了,方便吗?