Python:从类内部访问静态类变量

时间:2012-07-27 02:28:16

标签: python python-3.x metaprogramming static-variables class-variables

所以我正在尝试创建一个扩展列表的类,具有某些特殊属性映射的额外功能,以引用列表的某些部分。使用this Py3k doc page,我创建了以下代码。我的想法是(假设我有sequence此类的实例)sequence.seq应该与sequence[0]完全相同,而sequence.index应该与sequence[2]完全相同,等。

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

我找到this 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

2 个答案:

答案 0 :(得分:1)

您可以使用点(.)访问属性,而不是使用[]。 Python不允许您省略self引用,因此您需要使用self.__map__访问类变量。因此,如果您想要访问该位置的元素,则需要self[self.__map__[name]]

请注意,为您自己的目的使用双下划线夹名并不是一个好主意。即使是两个领先的下划线(名称错误)通常比您需要的更多。如果您只是想向用户表明__map__属性不属于公共API,请将其称为_map

答案 1 :(得分:1)

由于在完全定义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