如何在python中动态添加和绑定描述符?

时间:2017-06-14 15:31:21

标签: python class getter-setter

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

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

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'

是否有一个更简单的解决方案,减少了kludges?

1 个答案:

答案 0 :(得分:2)

所以,你的__init__容器就在那里。你遇到的问题:

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

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

    您在班级范围内设置foobar - 字面意思是类属性。但是以你的“动态”方式,你是用实例做的。 Idk如果你试图将它设置为类,但如果这是一个意图,super不会像这样工作。要动态设置附加描述符,您需要将其附加到实例的类(由self内的__init__引用)。为此,请访问self.__class__type(self)。所以,您的代码可能看起来像

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