Python:描述符列表

jes*_*hep 5 python list descriptor

我试图使用列表来引用一系列描述符,但没有成功.有一个_b由外部库()定义的对象列表(class A)我想通过描述符(class Descriptor)访问.在下面的示例中,b分配了对描述符的引用列表,但是当为列表的任何项分配值时,对该描述符的引用将被值覆盖,而不是将值传递给描述符.即使在阅读了几篇关于描述符的引用和文章之后,我显然也缺少描述符的基本行为.

class Descriptor(object):
    def __init__(self, varname):
        self.varname = varname
        pass

    def __get__(self, instance, owner):
        print('get', self.varname)
        #return getattr(getattr(instance, self.varname),"get")()
        return instance.__dict__[self.varname].get()

    def __set__(self, instance, value):
        print('set', self.varname)
        #getattr(getattr(instance, self.varname),"set")(value)
        instance.__dict__[self.varname].set(value)

class A(object):
    def __init__(self, value=None):
        self.value = value
    def get(self):
        return self.value
    def set(self, value):
        self.value = value

class C(object):
    print "root"
    a = Descriptor('_a')
    b = [Descriptor('_b[x]') for x in range(5)]
    def __init__(self, val):
        print "init"
        self._a = A()
        self.a = val
        self._b = [A() for x in range(5)]
        self.b[0] = 1
c = C(3)
d = C(4)

print c._a.get()
print c.a
print d._a.get()
print d.a
print c.b[0]
Run Code Online (Sandbox Code Playgroud)

在我的实际程序中,外部库是一个gui库,我想抽象,因此可以轻松地交换不同的接口.gui中的几个视图包含与程序中的列表对应的输入框列(每列最多40个).

此外,这是访问传递给描述符的实例对象的成员函数的首选方法:getattr__dict__.__dict__看起来更干净但我不知道在使用它时是否存在任何框架或可用性问题.

我们对所提问题的任何帮助或对满足我在该计划中的需求的其他方法的建议表示赞赏.谢谢.

根据每毫米的推荐,以下类似列表的类似乎满足了我的需求.使用此方法的任何陷阱除了在类根中定义的描述符而类中的'列表描述符' __init__以及在初始化时必须提供类作为参数?需要添加其他列表函数,并且需要添加特殊索引行为,例如负索引.

class DescriptorList(object):
    def __init__(self, owner, varname):
        self.owner = owner
        self.varname = varname

    def __getitem__(self, index):
        print('getitem', self.varname, index)
        return getattr(getattr(self.owner, self.varname)[index],"get")()

    def __setitem__(self, index, value):
        print('setitem', self.varname, index)
        getattr(getattr(self.owner, self.varname)[index],"set")(value)

class C(object):
    a = Descriptor('_a')
    def __init__(self, val):
        self._a = A()
        self.a = val
        self._b = [A() for x in range(5)]
        self.b = DescriptorList(self, '_b')
        for i in range(5):
            self.b[i] = i

c = C(3)
print [c.b[i] for i in range(5)]
Run Code Online (Sandbox Code Playgroud)

此外,通过DescriptorList实例化C.__init__,可以简化代码,以便DescriptorList使用对象本身而不是对象的名称.这种方法有什么优点或缺点吗?

class DescriptorList(object):
    def __init__(self, var):
        self.var = var

    def __getitem__(self, index):
        print('get', self.var, index)
        return self.var[index].get()

    def __setitem__(self, index, value):
        print('set', self.var, index)
        self.var[index].set(value)

class C(object):
    a = Descriptor('_a')
    def __init__(self, val):
        self._a = A()
        self.a = val
        self._b = [A() for x in range(5)]
        self.b = DescriptorList(self._b)
        for i in range(5):
            self.b[i] = i
Run Code Online (Sandbox Code Playgroud)

为什么__get____set__从不同的处理__getitem____setitem__

jes*_*hep 0

根据 millimoose 和另一篇性质相似的帖子的反馈,以下代码似乎满足我的需求,尽管它看起来有点混乱。

class Descriptor(object):
    def __init__(self, varname, index=None):
        self.varname = varname
        self.index = index

    def __get__(self, instance, owner):
        print('get', self.varname, self.index)
        if self.index is not None:
            return getattr(getattr(instance, self.varname)[self.index],"get")()
        else:
            return getattr(getattr(instance, self.varname),"get")()

    def __set__(self, instance, value):
        print('set', self.varname, self.index)
        if self.index is not None:
            getattr(getattr(instance, self.varname)[self.index],"set")(value)
        else:
            getattr(getattr(instance, self.varname),"set")(value)

class DescriptorList(list):
    def __init__(self, initlist, instance):
        self.instance = instance
        super(DescriptorList,self).__init__(initlist)

    def __getitem__(self, index):
        print('getitem', self.instance, index)
        return super(DescriptorList,self).__getitem__(index).__get__(self.instance, self.instance.__class__)

    def __setitem__(self, index, value):
        print('setitem', self.instance, index, value)
        super(DescriptorList,self).__getitem__(index).__set__(self.instance, value)

class A(object):
    def __init__(self, value=None):
        self.value = value
    def get(self):
        return self.value
    def set(self, value):
        self.value = value

class C(object):
    a = Descriptor('_a')
    b = [Descriptor('_b', x) for x in range(5)]

    def __init__(self, val):
        self._a = A()
        self.a = val
        self._b = [A() for x in range(5)]
        self.b = DescriptorList(self.__class__.b, self)
        for i in range(5):
            self.b[i] = i*val

c = C(3)
d = C(4)
print c.a
print d.a
print [c.b[i] for i in range(5)]
print [d.b[i] for i in range(5)]
Run Code Online (Sandbox Code Playgroud)

任何有关此解决方案的限制或错误的评论或建议的改进都将受到赞赏。