我试图使用列表来引用一系列描述符但没有成功。有一个由外部库(_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]
在我的实际程序中,外部库是一个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)]
此外,在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
为什么__get__
和__set__
的处理方式与__getitem__
和__setitem__
不同?
答案 0 :(得分:0)
根据millimoose和another post的反馈,性质相似,以下代码似乎可以满足我的需求,虽然它似乎有点像kludge。
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)]
对此解决方案的限制或错误或建议的改进的任何评论都表示赞赏。
答案 1 :(得分:0)
我需要类似的东西,我想出了以下内容:
class Element(object):
def __get__(self, obj, objtype=None):
print("Element.__get__(), obj.idx={0}".format(obj.idx))
return random.randint(1, 10)
def __set__(self, obj, value):
print("Element.__set__(), obj.idx={0}, value={1}".format(obj.idx, value))
class Indexable(object):
# Can also sub-class from list; I needed mine to be fixed length
# because I was mapping them to a set of hardware registers.
element = Element()
def __init__(self, sz):
self.sz = sz
self.idx = 0
def __getitem__(self, idx):
self.idx = idx
return self.element
def __setitem__(self, idx, value):
self.idx = idx
self.element = element
class Owner(object):
def __init__(self):
self.seq = Indexable(5)
Element.__get__
调用random.randint()但很明显,它是任意的。我需要的是索引,因此get / set函数知道要读/写哪个寄存器。