【问题标题】:How to add and bind descriptors dynamically in python?如何在python中动态添加和绑定描述符?
【发布时间】:2017-06-14 15:31:21
【问题描述】:

我想将描述符动态绑定到类的属性。

例如我有这个描述符(它只是一个虚拟的例子):

class Item(object):
    def __init__(self, filename):
        self.filename = filename

    def __get__(self, obj=None, objtype=None):
        #print '__get__(%s, %s)' % (obj, objtype)
        return open(self.filename).read()

    def __set__(self, obj, val):
        #print '__set__(%s, %s)' % (obj, val)
        open(self.filename, 'w').write(str(val))

在我的主容器中,我想动态注册我的描述符。

如果我在类级别实例化描述符,一切都会很好:

class Container(object):
    foo = Item('foo')
    bar = Item('bar')

不幸的是,当我尝试使用 setattr 动态关联描述符时,我需要为我的类添加更多复杂性:

class Container(object):
    def __init__(self, data):
        for attr in data:
            super(Container, self).__setattr__(attr, Item(attr))

    def __setattr__(self, name, value):   
        #print '__setattr__(%s, %s)' % (name, value)
        attr = super(Container, self).__getattribute__(name)
        if hasattr(attr, '__set__'):
            attr.__set__(name, value)
        else:
            super(Container, self).__setattr__(name, value)        

    def __getattribute__(self, name):
        #print '__getattribute__(%s)' % (name)
        attr = super(Container, self).__getattribute__(name)
        if hasattr(attr, '__get__'):
            return attr.__get__(name)
        return attr

预期的输出是:

>>> c = Container(['foo', 'bar'])  
>>> c.foo = 2
>>> c.foo
'2'

有没有更简单的解决方案?

【问题讨论】:

  • 请不要"completely rewrite the question"。不要成为chameleon。使现有答案无效的重大修改会受到社区的反对。
  • @AndrasDeak 那有什么解决办法呢?我的问题不清楚,我不能删除它,我也不能朝同一个错误的方向前进。我问的不一样。最终最初的目标是相同的。
  • 我没有仔细阅读您的问题和编辑,我只看到一个 4k 代表用户提出问题,然后离开 cmets 关于“完全重写问题”,然后删除其中一个答案.如果您认为原件不清楚并且现有问答对中没有任何意义,那很好。我只是想让你有意识地意识到重写问题的问题(太多的用户没有)。

标签: python class getter-setter


【解决方案1】:

所以,您的 __init__ 在容器中就快到了。您遇到的问题:

  1. 在 99.9% 的情况下,您永远不会直接调用魔法 (dunder, __) 函数。所以,你的super(...).__setattr__ 没有意义,tbh。这个有setattr
  2. 描述符的棘手部分(顺便说一句,根据我的经验,当人们开始使用它们时,这是一种“默认”障碍)。当您以非动态方式使用描述符时

    class Container(object):
        foo = Item('foo')
        bar = Item('bar')
    

    您在类的范围内设置foobar - 字面意思是类属性。但是以您的“动态”方式,您正在使用实例进行操作。如果您尝试将其设置为类,我想知道,但如果这是有意的,super 不会像这样工作。要动态设置附加描述符,您需要将其附加到实例的类(由self 内部__init__ 引用)。为此,请访问 self.__class__type(self)。所以,你的代码可能看起来像

    class Container(object):
        def __init__(self, data):
            for attr in data:
                setattr(type(self), attr, Item(attr))
    

【讨论】:

  • 我使用您的输入完全重写了这个问题。你能更新你的答案吗?
  • 我有一个会被多次调用的类,每个类都应该有唯一的属性。有没有办法在不定义 __init__ 中的类的情况下做到这一点?
  • 请为您的案例创建单独的问题示例,当您期望具体答案时,很难回答抽象问题;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-04
  • 1970-01-01
  • 2020-02-06
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
相关资源
最近更新 更多