【问题标题】:Dynamically adding @property in python在python中动态添加@property
【发布时间】:2011-02-26 14:44:56
【问题描述】:

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

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(),self 将被正确绑定,一切正常。

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

我猜是这样的:

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

但是,这样做instance.my_method 会返回一个属性对象。

【问题讨论】:

  • @Bo Persson:虽然问题的标题 python: How to add property to a class dynamic? 基本相同,但我不相信它接受的答案(包括附加组件)一般地解决了这个问题。
  • @martineau - 似乎也没有其他人相信这一点,所以很早就结束了投票。
  • @BoPersson:我的立场是正确的,从技术上讲,added-on answer 中针对该问题的信息确实解决了一般问题。
  • 这个类的其他实例有这个属性重要吗?

标签: python


【解决方案1】:

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

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

注意: 添加另一个答案,因为我认为 @Alex Martelli 虽然正确,但通过创建一个包含该属性的新类来实现预期的结果,这个答案旨在更直接/直截了当没有将发生的事情抽象到它自己的方法中。

【讨论】:

  • -1,这不仅会影响my_instance 的行为,还会为type(my_instance) 类的所有其他实例设置my_prop
  • @ali_m,对,这就是目的,将属性添加到类中,上面的答案(被检查为正确的答案)。也在将属性添加到类(而不是实例)。
  • 不,cls = type(cls.__name__, (cls,), {}) 创建了一个新的“per-instance”类,其基类是我们添加属性的实例的类型。然后,当您按照 Blckknght 的评论分配 inst.__class__ = cls 时,这会导致该属性仅应用于 inst,而不是应用于 type(inst) 类的所有实例。
  • 答案不是分配__class__(在评论中建议)。无论如何,OP 都没有明确询问如何将属性添加到特定的类实例,如果是这样的话……我的回答是不正确的。
【解决方案2】:

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

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))

我用一个属性标记这些特殊的“每个实例”类,以避免在同一个实例上执行多个addprop 调用时不必要地创建多个。

请注意,与property 的其他用途一样,您需要使用的类是new-style(通常通过直接或间接从object 继承获得),不是默认分配给没有基础的类的古老遗留样式(在 Python 3 中删除)。

【讨论】:

  • 我刚刚点击了这个答案的链接,发现它非常有用。然而,也许是由于过去几年 Python 的变化,有些东西对我来说不是开箱即用的。我必须将cls.hasattr('__perinstance') 更改为hasattr(cls, '__perinstance'),并且我必须在if 块中添加一行:inst.__class__ = cls。我希望这可以帮助其他看到此答案的人让它为他们工作!
  • @Blckknght:我看不出最初的答案是如何起作用的,因为它不会在发生这种情况时将实例的类更改为新创建的“每个实例”。跨度>
猜你喜欢
  • 2018-10-31
  • 2018-11-23
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
相关资源
最近更新 更多