Редактировать :
См. Мой полный ответ внизу этого вопроса.
tl; dr answer : Python имеет статически вложенные области видимости. Статическая мы можем получить доступ к функциям во внешней области видимости.
Примечание : как Фредерик указал ниже, эта функция, похоже, не работает. Вместо этого см. Пример 5 (и далее).
Пример 3.
>>> def myfunc(): ... x = 3 ... class MyClass(object): ... x = x ... return MyClass ... >>> myfunc().x Traceback (most recent call last): File "
", line 1, in File " ", line 3, in myfunc File " ", line 4, in MyClass NameError: name 'x' is not defined
По сути, это то же самое, что и в примере 1: мы получаем доступ к внешней области из определения класса, только на этот раз эта область не является глобальной, спасибоmyfunc ()
.Редактировать 5: Как @ user3022222 указано ниже , я испортил этот пример в своей исходной публикации. Я считаю, что это не удается, потому что только функции (а не другие блоки кода, такие как это определение класса) могут получить доступ к переменным в охватывающей области. Для блоков нефункционального кода доступны только локальные, глобальные и встроенные переменные. Более подробное объяснение доступно в этом вопросе
Еще одно:
Пример 4.
>>> def my_defining_func(): ... def mymethod(self): ... return self.y ... class MyClass(object): ... mymethod = mymethod ... y = 3 ... return MyClass ... >>> my_defining_func() Traceback (most recent call last): File "
", line 1, in File " ", line 4, in my_defining_func File " ", line 5, in MyClass NameError: name 'mymethod' is not defined Гм ... извините?
Чем это отличается от примера 2?
Я полностью сбит с толку. Пожалуйста, разбери меня. Спасибо!
PS на случай, если это не просто проблема с моим пониманием, я пробовал это на Python 2.5.2 и Python 2.6.2. К сожалению, это все, к чему у меня сейчас есть доступ, но они оба демонстрируют одинаковое поведение.
Править Согласно http://docs.python.org/tutorial/classes.html#python-scopes-and-namespaces : в любой момент во время выполнения существует как минимум три вложенных области, чьи пространства имен доступны напрямую :
- самая внутренняя область видимости, которая искали первым, содержит местный наименования
- области применения любых ограждающих функции, которые ищутся начиная с ближайшего окружающего область, содержит нелокальные, но также неглобальные имена
- предпоследняя область видимости содержит глобальные имена текущего модуля
- крайняя область видимости (поиск был последним) это пространство имен, содержащее встроенный имена
# 4. кажется контрпримером ко второму из них.
Редактировать 2
Пример 5.
>>> def fun1(): ... x = 3 ... def fun2(): ... print x ... return fun2 ... >>> fun1()() 3
Редактировать 3
Поскольку @ Frédéric указал на присвоение переменной с тем же именем, что и у нее во внешней области видимости «маскирует» внешнюю переменную, препятствуя работе присваивания.
Итак, эта модифицированная версия примера 4 работает:
def my_defining_func(): def mymethod_outer(self): return self.y class MyClass(object): mymethod = mymethod_outer y = 3 return MyClass my_defining_func()
Однако это не так:
def my_defining_func(): def mymethod(self): return self.y class MyClass(object): mymethod_temp = mymethod mymethod = mymethod_temp y = 3 return MyClass my_defining_func()
Я до сих пор не совсем понимаю почему происходит это маскирование: не должно ли происходить связывание имени, когда происходит присвоение?
Этот пример, по крайней мере, предоставляет некоторую подсказку (и более полезное сообщение об ошибке):
>>> def my_defining_func(): ... x = 3 ... def my_inner_func(): ... x = x ... return x ... return my_inner_func ... >>> my_defining_func()() Traceback (most recent call last): File "
", line 1, in File " ", line 4, in my_inner_func UnboundLocalError: local variable 'x' referenced before assignment >>> my_defining_func() Таким образом, похоже, что локальная переменная определена в функции создание (которое завершается успешно), в результате чего локальное имя становится «зарезервированным» и таким образом маскирует имя внешней области при вызове функции.
Интересно. определены текстуально: глобальные объем функции, определенной в модуль - это пространство имен этого модуля, нет независимо от того, откуда и под каким псевдонимом функция вызывается. С другой стороны, фактический поиск имен выполняется динамически, во время выполнения - однако, определение языка развивается в сторону статического разрешения имен, при Время «компиляции», поэтому не полагайтесь на динамическое разрешение имен! (По факту, локальные переменные уже определены статически.)
Редактировать 4
Реальный ответ
Это, казалось бы, сбивающее с толку поведение вызвано статически вложенными областями действия Python, как определено в PEP 227 . На самом деле это не имеет ничего общего с PEP 3104 .
Из PEP 227:
Правила разрешения имен являются типичными для языков со статической областью видимости [...] [кроме] переменные не объявляются. Если происходит операция привязки имени в любом месте функции, тогда это имя рассматривается как локальный для функции и все ссылки относятся к местным привязка. Если ссылка встречается до имя связано, NameError поднял.
[...]
Пример Тима Петерса демонстрирует потенциальные ловушки вложенные области при отсутствии объявлений:
i = 6 def f (x): def g (): распечатать я # ... # перейти на следующую страницу # ... for i in x: # ah, i * является * локальным для f, так что это то, что видит g проходить г()
Вызов g () будет ссылаться на переменную i, связанную в f () с помощью for петля. Если g () вызывается до выполнения цикла, ошибка NameError будет статически вложенные области видимости обеспечивают то, что Алекс Мартелли назвал «единственной наиболее важной оптимизацией, которую делает компилятор Python: локальные переменные функции не хранятся в dict, они находятся в узком векторе значений, и каждая локальная доступ к переменной использует индекс в этом векторе, а не поиск по имени. "