Подтвердить что ты не робот

Подкласс python доступа к переменной класса родительского

Я был удивлен, узнав, что переменная класса подкласса не может получить доступ к переменной класса родителя без специального указания имени класса родителя:

>>> class A(object):
...     x = 0
... 
>>> class B(A):
...     y = x+1
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in B
NameError: name 'x' is not defined
>>> class B(A):
...     y = A.x + 1
... 
>>> B.x
0
>>> B.y
1

Почему это так, что при определении B.y я должен ссылаться на A.x, а не только на x? Это противоречит моей интуиции из переменных экземпляра, и поскольку я могу ссылаться на B.x после определения B.

4b9b3361

Ответ 1

В Python тело класса выполняется в собственном пространстве имен до создания класса (после чего члены этого пространства имен становятся членами класса). Поэтому, когда интерпретатор достигает y = x + 1, класс B еще не существует в этой точке и, следовательно, не имеет родителя.

Подробнее см. http://docs.python.org/reference/compound_stmts.html#class-definitions

Ответ 2

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

В любое время, когда вам нужен другой поиск, вы будете использовать квалифицированное имя, а не голый. Квалифицированные имена значительно более мощные, потому что поиск всегда может быть делегирован объектам, чьи атрибуты могут быть запрошены, и этот объект может реализовать любые правила поиска, в которых они нуждаются. В частности, в методе экземпляра внутри класса self.x можно задать объект self для поиска имени атрибута 'x' - и в этом поиске он может делегировать классы, включая реализацию концепции наследования (и множественного наследования, порядка разрешения метода и т.д.).

Тело класса (в отличие от тел методов, определенных в классе) выполняется как часть оператора class, до, объект класса создается или его имя привязано (в частности, до того, как любая из баз была определена как основа, хотя эта последняя деталь никогда не имеет значения при обращении к именам в любом случае! -).

Итак, в вашем примере, в классе B, barename x просматривается с помощью универсальных правил - это локальное имя? Если нет, то он связан в любой внешней функции, в которой этот объем вложен? Если нет, то он связан как глобальный или встроенный? Если ни одно из вышеперечисленных вопросов, использующее указанное имя barename, вызывает исключение ошибки имени.

Поскольку вам нужна другая последовательность поиска, чем правила поиска barename универсально, тогда вам явно нужно использовать квалифицированное имя, а не имя-бар; и мгновенное отражение ясно покажет, что "один очевидный выбор" для квалифицированного имени, используемого для вашей цели, должен быть A.x - с тех пор, когда вы хотите, чтобы он был просмотрен (базы не были записаны нигде но в этот момент, в конце концов, это будет метакласс, обычно type, который будет выполнять привязки баз как часть своей работы, когда он будет вызван после того, как тело класса будет исполнено! -).

Некоторые люди так остро привязаны к другим "магическим" правилам поиска барменов, которые просто не могут выдержать этот аспект Python (изначально вдохновленный, по-моему, Modula-3, немного известным языком, который очень хорошо рассмотренный в кругах теоретиков; -) - нужно написать self.x в методе, чтобы указать, что x нужно искать на self, а не использовать универсальные правила barename, например, диски таких людей batty.

Мне нравится простота и универсальность правил поиска в barename, и я люблю использовать квалифицированные имена вместо barenames в любое время, когда хочу любую другую форму поиска... но тогда это не секрет, что я безумно влюбленный в Python (у меня есть свои собственные ворчания - например, global x), поскольку оператор всегда меняет обход моего сайта, где я бы скорее написал global.x, т.е. иметь global имя встроенного "текущий исполняемый модуль"... я do люблю квалифицированные имена! -), не так ли? -)