Почему параметр "name" для __setattr__ включает класс, а __getattr__ нет? - PullRequest
2 голосов
/ 05 марта 2010

Следующий код:

class MyClass():
    def test(self):
        self.__x = 0

    def __setattr__(self, name, value):
        print name

    def __getattr__(self, name):
        print name
        raise AttributeError(name)

x = MyClass()
x.test()
x.__y

Выходы:

_MyClass__x
__y
Traceback (most recent call last):
...
AttributeError: __y

Документация совершенно бесполезна, поскольку «имя» является «именем атрибута», но по какой-то причинеэто зависит от того, устанавливаете ли вы его или получаете.

То, что я хочу знать, это:

  • Я что-то здесь не так делаю?
  • Какполучить x в первом случае вместо _MyClass__x?

Ответы [ 2 ]

4 голосов
/ 05 марта 2010

Двойное подчеркивание вызывает искажение имени. Если вам не нужно искажение имени, не используйте двойное ноль: 1001 *

Что означает одиночное и двойное подчеркивание перед именем объекта?

Из документов Python

9,6. Частные переменные

«Частные» переменные экземпляра, к которым нельзя получить доступ, кроме как внутри объекта, в Python не существуют. Однако существует соглашение, которому следует большая часть кода Python: имя с префиксом подчеркивания (например, _spam) следует рассматривать как непубличную часть API (будь то функция, метод или данные). членом). Он должен рассматриваться как деталь реализации и может быть изменен без уведомления.

Поскольку существует действительный вариант использования для закрытых членов класса (а именно, чтобы избежать столкновения имен имен с именами, определенными подклассами), существует ограниченная поддержка такого механизма, называемого искажение имени. Любой идентификатор вида __spam (по крайней мере два начальных подчеркивания, самое большее одно конечное подчеркивание) текстуально заменяется на _classname__spam, где classname - это текущее имя класса с удаленными начальными подчеркиваниями. Это искажение выполняется без учета синтаксической позиции идентификатора, если оно происходит в определении класса.

Обратите внимание, что правила искажения разработаны главным образом, чтобы избежать несчастных случаев; все еще возможно получить доступ или изменить переменную, которая считается частной. Это может быть даже полезно в особых обстоятельствах, таких как отладчик.

Обратите внимание, что код, переданный exec, eval() или execfile(), не считает имя класса вызывающего класса текущим классом; это похоже на действие глобального оператора, действие которого также ограничено кодом, который скомпилирован вместе. То же ограничение применяется к getattr(), setattr() и delattr(), а также к ссылкам __dict__ напрямую.

1 голос
/ 05 марта 2010

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

...