Вопрос

Итак, я пытаюсь создать класс, расширяющий список, с дополнительной возможностью сопоставления определенных специальных атрибутов для ссылки на определенные части списка.С использованием эта страница документа Py3k, я создал следующий код.Идея состоит в том, что (скажем, у меня есть sequence экземпляр этого класса) sequence.seq должен действовать точно так же, как sequence[0], и sequence.index должен действовать точно так же, как sequence[2], и т. д.

Кажется, это работает отлично, за исключением того, что я не могу получить доступ к атрибутам сопоставления переменных класса в списке.

я нашел это ТАК вопрос, но либо ответ там неправильный, либо внутри методов что-то другое.Я также мог бы использовать 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
Это было полезно?

Решение

Поскольку ни один из методов не вызывается до тех пор, пока 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

Другие советы

Вы получаете доступ к атрибутам с помощью точки (.), не с [].Python не позволяет вам опускать self ссылку, поэтому вам нужно получить доступ к переменной класса с помощью self.__map__.Итак, если вы хотите получить доступ к элементу в этой позиции, вам нужно self[self.__map__[name]].

Обратите внимание: не рекомендуется использовать имена с двойным подчеркиванием в своих целях.Даже двух символов подчеркивания в начале (которые искажают имена) обычно больше, чем вам нужно.Если вы просто хотите указать пользователям, что __map__ атрибут не является частью общедоступного API, назовите его _map.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top