Этот вопрос является продолжением вопроса о области видимости переменной Python . Дополнительные вопросы q1 , q2 и ответы можно найти на SO, и даже больше.
Официальная документация Python и PEP 3104 должны объяснять детали, но они не кажутся мне полностью понятными.
Тема, которую я пытаюсь решить, - это рефакторинг кода, содержащего nonlocal
/ global
, путем перемещения этого кода вверх / вниз на один уровень иерархии.
Что я не понимаю, так это значение этого предложения из ссылки на Python:
Имена, перечисленные в нелокальном утверждении, в отличие от имен, перечисленных в
глобальное утверждение, должно ссылаться на ранее существовавшие привязки во вложении
область действия (область, в которой должна быть создана новая привязка, не может быть
определяется однозначно).
Учитывая следующий код в глобальной области видимости:
var = 0
def outer():
global var # line A
var = 1
def inner():
nonlocal var # line B
var = 2
print('inner:', var)
inner()
print('outer:', var)
outer()
print('main:', var)
При выполнении возникает ошибка:
SyntaxError: no binding for nonlocal 'var' found
Код работает (конечно, с другой семантикой, если любая строка A закомментирована:
inner: 2
outer: 2
main: 0
или строка B закомментирована:
inner: 2
outer: 1
main: 1
Однако в вышеприведенном примере, и поскольку nonlocal
должен связывать var с "включающей областью действия", я ожидал, что строка A связывает внешний / var с глобальной областью действия, а строка B затем ищет внешний / var, а также связывает внутренний / var с глобальным / var. Вместо этого он, кажется, вообще не находит его (из-за повторного связывания в строке A) и выдает ошибку.
Желаемый результат, который я ожидал, был:
inner: 2
outer: 2
main: 2
Это только еще один пример запутанного состояния ума в области видимости в Python?
Или, чтобы сделать это конструктивным вопросом:
- Как можно написать такой пример таким образом, чтобы не имело значения, на каком уровне находится функция (необходимость обмена
global
с nonlocal
и наоборот)?
- Если функции находятся на промежуточном и неизвестном уровне иерархии, как мог автор
outer()
изменить код, который не должен касаться ни самого внешнего (в данном случае глобального) уровня, ни уровня inner()
? -
В моем скромном понимании языка подобных конструкций (зависимостей от замыканий) просто следует избегать. Другие уже предложили использовать другие языковые функции ( классы , func attrs ) для достижения такого рода чувствительности к контексту.