Python在运行时添加方法

时间:2016-06-13 06:57:45

标签: python class methods class-method

我试图在运行时动态地向类添加方法,并且看到了一些问题:

#Here we define a set of symbols within an exec statement and put them into the dictionary d
d = {}
exec "def get_%s(self): return self.%s" % (attr_name, attr) in d

#Now, we bind the get method stored in d['get_%s'] to our object (class)
func = d['get_%s' % (attr_name)].__get__(d['get_%s' % (attr_name)], class)
setattr(class_instance, func.__name__, func)

当我尝试调用生成的get方法时,我看到如下:

Traceback (most recent call last):
  File "Textere_AdvancedExample.py", line 77, in <module>
    count = fact.get_counter()
  File "<string>", line 1, in get_counter
AttributeError: 'function' object has no attribute '_counter'

修改

根据迄今为止给出的一些特殊回应,我想我需要澄清为什么我这样做。

我正在尝试构建一个类似下面示例的注释:

@getters
@singleton
class A() {

    def __init__(self):
        self._a = "a"
        self._b = "b"
 }

根据类中的名称,注释将在运行时为私有类变量构建getter,并将它们绑定到singleton实例。

我采取的策略是使用一组带有一组dicts的Application Context类。然后,将上下文传递给注释,该注释添加实例&amp;分为这些词组。

启动时,应用程序上下文负责阅读词典,然后构建&amp;将get方法绑定到相应的单例对象。

EDIT2

所以这个开发是在与我的朋友们进行了一些讨论后开始的,他们是Java开发人员,特别是两个库:Spring&amp; Lombok

我想看看这些特定的功能是否可以在Python中实现。因此,应用程序上下文最初来自尝试获得类似于Spring的autowire注释的功能。我没有问题就这样做了。

然后,我得到了getter和setter的生成,并意识到我将从Java实现中获得Python的根本区别:Lombok在编译时执行此操作而Python未编译。这意味着我必须根据被注释的内容动态生成方法,并在运行时手动将它们绑定到对象。因此,您会看到Java实现的这种扭曲。

对于有兴趣的人,可以找到完整的代码here

2 个答案:

答案 0 :(得分:6)

您可以轻松地动态添加静态方法或类方法:

class A:
    pass

@staticmethod
def foo0(x):
    return x * 2

a = A()
A.foo = foo0
a.foo(3)

返回6

class A:
    val = 3

@classmethod
def foo0(cls, x):
    return x * cls.val

a = A()
A.foo = foo0
a.foo(2)

返回6

您还可以将特定方法添加到类的实例(几乎相同的方式)

class A:
    pass

a = A()
a.foo = (lambda x: 2*x)
a.foo(3)

返回6

您还可以通过使用types模块将实例方法添加到类中(事实上,这种通用方法也可用于创建静态和类方法,以及仅实例方法) :

class A:
    def __init__(self, val):
        self.val = val


a = A(3)
A.foo = types.MethodType((lambda self, x: self.val * x), None, A)
a.foo(2)

返回6

但这真的是monkey patching,这是一个快速而又脏的黑客攻击,只有当你需要传递稍微改变的类并且不允许你更改名字时才能使用它。向类添加功能的漂亮而干净的方法是继承

为了使这个答案更好,上面的内容适用于Python 2。

对于Python 3,只能使用第一种创建类和静态方法的方法,因为types模块丢失了很多类型。

您可以像以下一样创建实例方法:

class A:
    def __init__(self, val):
        self.val = val


a = A(3)
A.foo = (lambda self, x: self.val * x)
a.foo(2)

返回6。这里不需要特殊构造

答案 1 :(得分:0)

exec("%s.__dict__['get_%s'] = lambda self: self.%s" % (class_name, attr_name, attr_name))