1

所以我正在尝试创建一个扩展列表的类,具有将某些特殊属性映射到引用列表的某些部分的额外能力。使用这个 Py3k 文档页面,我创建了以下代码。这个想法是(假设我有sequence这个类的一个实例)sequence.seq应该完全像sequence[0],并且sequence.index应该完全像sequence[2],等等。

它似乎工作得很好,除了我似乎无法访问列表的类变量映射属性。

我发现了这个 SO question,但是答案有误,或者方法中的某些内容有所不同。我也可以使用self.__class__.__map__,但因为我需要里面的类变量__getattribute__,所以我进入了一个无限递归循环。

>>> class Sequence(list):
...      __map__ = {'seq': 0,
...                 'size': 1,
...                 'index': 2,
...                 'fdbid': 3,
...                 'guide': 4,
...                 'factors': 5,
...                 'clas': 6,
...                 'sorttime': 7,
...                 'time': 8,
...                 'res': 9,
...                 'driver': 10 }
...      
...      def __setattr__(self, name, value): # "Black magic" meta programming to make certain attributes access the list
...           print('Setting atr', name, 'with val', value)
...           try:
...                self[__map__[name]] = value
...           except KeyError:
...                object.__setattr__(self, name, value)
...      
...      def __getattribute__(self, name):
...           print('Getting atr', name)
...           try:
...                return self[__map__[name]]
...           except KeyError:
...                return object.__getattribute__(self, name)
...      
...      def __init__(self, seq=0, size=0, index=0, fdbid=0, guide=None, factors=None, 
...           sorttime=None, time=None):
...                super().__init__([None for i in range(11)]) # Be sure the list has the necessary length
...                self.seq = seq
...                self.index = index
...                self.size = size
...                self.fdbid = fdbid
...                self.guide = ''
...                self.time = time
...                self.sorttime = sorttime
...                self.factors = factors
...                self.res = ''
...                self.driver = ''
... 
>>> a = Sequence()
Setting atr seq with val 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 31, in __init__
  File "<stdin>", line 17, in __setattr__
NameError: global name '__map__' is not defined
4

2 回答 2

1

由于在 after 完全定义之前不会调用任何方法Sequence,因此您可以Sequence.__map__毫无困难地参考。例如:

def __setattr(self, name, value):
    print('Setting atr', name, 'with val', value)
    try:
        self[Sequence.__map__[name]] = value
    except KeyError:
        object.__setattr__(self, name, value)

顺便说一句,这是一个演示,只要不存在同名的实例属性,就可以通过对象访问类属性:

class Foo:
    i = 3
    def __init__(self, overwrite):
        if overwrite:
            self.i = 4

f = Foo(False)
id(f.i) == id(Foo.i)     # Should be True
f = Foo(True)
id(f.i) == id(Foo.i)     # Should be False
于 2012-07-27T02:33:34.240 回答
1

您使用点 ( .) 访问属性,而不是使用[]. Python 不允许您省略self引用,因此您需要使用self.__map__. 所以如果你想访问那个位置的元素,你需要self[self.__map__[name]].

请注意,将双下划线夹在中间的名称用于您自己的目的并不是一个好主意。即使是两个前导下划线(会进行名称修改)通常也超出您的需要。如果您只想向用户表明该__map__属性不是公共 API 的一部分,请调用它_map

于 2012-07-27T02:31:05.953 回答