Python:描述符列表

标签 python list descriptor

我正在尝试使用列表来引用一系列描述符,但没有成功。我想通过描述符(class Descriptor)访问由外部库(class A)定义的对象列表(_b) ).在下面的示例中,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]

在我的实际程序中,外部库是一个 gui 库,我想将其抽象化,以便可以轻松地交换不同的界面。 gui 中的几个 View 包含与程序中的列表相对应的输入框列(每列最多 40 个)。

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

对于所提出问题的任何帮助或其他方法的建议以满足我在程序中的需求,我们将不胜感激。谢谢。

根据 millimoose 的推荐,以下类似列表的类似乎可以满足我的需求。除了类根中定义的描述符而类 __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)]

此外,DescriptorListC.__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

为什么 __get____set__ 的处理方式不同于 __getitem____setitem__

最佳答案

基于来自 millimoose 和 another post 的反馈这在本质上是相似的,下面的代码似乎可以满足我的需求,尽管它看起来有点困惑。

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

如有任何关于此解决方案的限制或错误的评论或建议的改进,我们将不胜感激。

关于Python:描述符列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13447017/

相关文章:

Python-向描述符添加属性

c - 为什么linux中不混合标准输入?

Python 日期系列生成

python - Windows+Python : Why is the first opened window not shown active?

python - Python 中要列出的字典

c# - 我应该更喜欢封闭式还是开放式列表<>系统?

python - 如何使用带有 pycurl 的 python 访问 Bugzilla 上错误的 XML 页面?

Python平台独立的获取系统信息的方式

python - 不确定如何引用元组列表中元组中的元素

c++ - 使用 vertex_descriptor boost graph 打印或迭代顶点