доступ подкласса Python к переменной класса parent - PullRequest
32 голосов
/ 06 сентября 2010

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

>>> 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.

Ответы [ 2 ]

48 голосов
/ 06 сентября 2010

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

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

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

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

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

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

Мне нравится простота и универсальность правил поиска по голым именам, и я люблю использовать квалифицированные имена вместо имен в любое время, когда я хочу любую другую форму поиска ... но тогда это не секрет, что я безумно влюблен в Python (у меня есть свои собственные ворчания - например, global x, поскольку утверждение всегда заставляет мою кожу ползать, где я бы лучше написал global.x, то есть иметь global be встроенное имя для «исполняемого в данный момент модуля» ... Я делаю люблю квалифицированные имена! -), так? -)

26 голосов
/ 06 сентября 2010

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

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

...