在python中动态添加@property

时间:2010-06-02 00:49:46

标签: python

我知道我可以通过执行以下操作动态地向对象添加实例方法:

import types
def my_method(self):
    # logic of method
# ...
# instance is some instance of some class
instance.my_method = types.MethodType(my_method, instance)

稍后我可以打电话给instance.my_method(),自我将被正确绑定,一切正常。

现在,我的问题:如何做同样的事情来获得用@property来装饰新方法的行为?

我猜想会像:

instance.my_method = types.MethodType(my_method, instance)
instance.my_method = property(instance.my_method)

但是,执行instance.my_method会返回一个属性对象。

2 个答案:

答案 0 :(得分:35)

property描述符对象需要存在实例中的而不是,才能获得您想要的效果。如果您不想更改现有类以避免更改其他实例的行为,则需要创建“每个实例类”,例如:

def addprop(inst, name, method):
  cls = type(inst)
  if not hasattr(cls, '__perinstance'):
    cls = type(cls.__name__, (cls,), {})
    cls.__perinstance = True
    inst.__class__ = cls
  setattr(cls, name, property(method))

我正在使用一个属性标记这些特殊的“per-instance”类,以避免在同一个实例上进行多次addprop调用时不必要地制作多个。

请注意,与property的其他用途一样,您需要在游戏中使用新式(通常通过直接或间接从object继承而获得) ,古老的遗留风格(在Python 3中删除),默认情况下分配给没有基础的类。

答案 1 :(得分:3)

由于这个问题不是要求添加到特定实例, 可以使用以下方法向类添加属性,这会将属性公开给YMMV类的所有实例。

cls = type(my_instance)
cls.my_prop = property(lambda self: "hello world")
print(my_instance.my_prop)
# >>> hello world

注意:添加另一个答案,因为我认为@Alex Martelli虽然正确,但是通过创建一个包含该属性的新类来实现所需的结果,这个答案旨在更加直接/直接没有抽象出自己的方法。