【问题标题】:Add attribute to python class将属性添加到 python 类
【发布时间】:2015-07-23 14:11:53
【问题描述】:

考虑以下代码:

class Foo():

    pass


Foo.entries = dict()


a = Foo()
a.entries['1'] = 1

b = Foo()
b.entries['3'] = 3

print(a.entries)

这将打印:

{'1': 1, '3': 3}

因为条目是作为静态属性添加的。有没有办法猴子修补类定义以添加新属性(不使用继承)。

我设法找到了以下方法,但对我来说看起来很复杂:

def patch_me(target, field, value):
    def func(self):
        if not hasattr(self, '__' + field):
            setattr(self, '__' + field, value())
        return getattr(self, '__' + field)
    setattr(target, field, property(func))

patch_me(Foo, 'entries', dict)

【问题讨论】:

  • 您正在添加一个在所有实例之间共享的 类属性。如果将其添加到实例中,实例已经创建是否应该获得新属性?
  • 你为什么不能改为a.entries = {'1': 1}

标签: python monkeypatching


【解决方案1】:

通常,属性要么通过__init__() 函数添加,要么在实例化之后添加:

foo = Foo()
foo.bar = 'something'  # note case

如果您想自动执行此操作,继承是迄今为止最简单的方法:

class Baz(Foo):
    def __init__(self):
        super().__init__()  # super() needs arguments in 2.x
        self.bar = 'something'

请注意,类不需要出现在 Python 模块的顶层。你可以在函数中声明一个类:

def make_baz(value):
    class Baz(Foo):
        def __init__(self):
            super().__init__()  # super() needs arguments in 2.x
            self.bar = value()
    return Baz()

此示例将在每次调用 make_baz() 时创建一个新类。这可能是也可能不是你想要的。这样做可能会更简单:

def make_foo(value):
    result = Foo()
    result.bar = value()
    return result

如果您真的打算对 original 类进行猴子修补,那么您提供的示例代码或多或少是最简单的方法。您可能会考虑对property() 使用装饰器语法,但这是一个小改动。我还应该注意,它不会调用双下划线名称修饰,这可能是一件好事,因为这意味着您不能与类本身使用的任何名称发生冲突。

【讨论】:

  • 类中的函数可以像 init 函数一样添加属性。事实上,您可以拥有销毁或添加属性的函数。例如绘制一个正方形类可以有一个边框方法。只有在调用边框方法时,该类才会获得边框属性。我更喜欢在 init 函数中为类似的东西添加一个border = 0 属性,但两种方式都可以。也许对于一个子类 BorderlessSquare。调用父级初始化函数并删除边框属性并添加一些其他属性。
猜你喜欢
  • 2021-07-26
  • 2018-03-16
  • 1970-01-01
  • 2019-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多