Три факта:
- имя (левая сторона) аргумента по умолчанию - это имя локальной переменной внутри тела функции.
- значение (правая сторона) аргумента по умолчанию оценивается в области, в которой определена функция, во время определения функции.
- Код в блоке класса выполняется во временном пространстве имен во время классаопределение. Блок класса не рассматривается как охватывающая область, что может удивить, если вы ожидаете поведение, подобное вложенному
def
.
Точка 3 является наиболее тонкой и, возможно, противоречит первоначальным ожиданиям. Это задокументировано в модели исполнения (раздел 4.2.2. Разрешение имен ):
Область имен, определенных в блоке класса, ограниченаблок класса;оно не распространяется на кодовые блоки методов
Вот почему имя bar
не разрешено во втором примере:
class Foo:
bar = 0
def __init__(self):
self.a = bar # name "bar" isn't accessible here, but code is valid syntax
Foo() # NameError: name 'bar' is not defined
Обратите внимание, что значение bar
, 0
, все равно будет доступен изнутри метода как атрибут класса: через Foo.bar
или self.bar
.
Теперь вы должны понять, почему последний пример работает :
class Foo:
bar = 0
def __init__(self, a=bar):
self.a = a
Foo()
И, учитывая пункты 1-3 выше, вы также должны быть в состоянии правильно предсказать, что здесь происходит:
class Foo:
def __init__(self, a=bar):
self.a = a
bar = 0
Foo()
Более подробная информация о странной области видимости приведена в UnboundLocalError: локальная переменная, на которую ссылается перед присваиванием, почему в этом случае правило LEGB не применяется .