Учитывая следующий код:
def A() :
b = 1
def B() :
# I can access 'b' from here.
print( b )
# But can i modify 'b' here? 'global' and assignment will not work.
B()
A()
Поскольку код в B()
функции переменной b
находится во внешней области, но не в глобальной области. Можно ли изменить b
переменную из B()
функции? Конечно, я могу прочитать это отсюда и print()
, но как это изменить?
python
python-2.7
Григорьевп
источник
источник
b
он изменен. Присвоениеb
маскирует внешнюю область видимости.nonlocal
не было перенесено в 2.x. Это неотъемлемая часть поддержки закрытия.Ответы:
В Python 3.x есть
nonlocal
ключевое слово . Я думаю, что это делает то, что вы хотите, но я не уверен, используете ли вы python 2 или 3.Для python 2 я обычно просто использую изменяемый объект (например, список или dict) и изменяю значение вместо переназначения.
пример:
Выходы:
источник
class nonlocal: pass
во внешней области видимости. Затемnonlocal.x
может быть назначен во внутренней области.SyntaxError
. ВозможноNonLocal
?Nonlocal
,? :-)Вы можете использовать пустой класс для хранения временной области. Это похоже на изменчивый, но немного красивее.
Это дает следующий интерактивный вывод:
источник
Я немного новичок в Python, но я немного читал об этом. Я считаю, что лучшее, что вы получите, похоже на обходной путь Java, который заключается в том, чтобы заключить вашу внешнюю переменную в список.
Изменить: я думаю, это было правдой до Python 3. Похоже,
nonlocal
это ваш ответ.источник
Нет, не можете, по крайней мере, таким образом.
Потому что «операция установки» создаст новое имя в текущей области видимости, которая покрывает внешнюю.
источник
Для тех, кто обратится к этому намного позже, есть более безопасный, но более сложный способ обхода. Без необходимости передавать переменные в качестве параметров.
источник
Короткий ответ, который будет работать автоматически
Я создал библиотеку python для решения этой конкретной проблемы. Он выпущен без лицензии, поэтому используйте его как хотите. Вы можете установить его
pip install seapie
или посетить домашнюю страницу здесь https://github.com/hirsimaki-markus/SEAPIEuser@pc:home$ pip install seapie
выходы
аргументы имеют следующее значение:
B()
, 1 означает родительскийA()
и 2 будет означать дедушку<module>
или бабушку aka globalДлинный ответ
Это более сложно. Seapie работает путем редактирования фреймов в стеке вызовов с помощью CPython api. CPython является стандартом де-факто, поэтому большинству людей не о чем беспокоиться.
Волшебные слова, которые вас, вероятно, заинтересуют, если вы читаете это, следующие:
Последний заставит обновления перейти в локальную область. однако локальные области видимости оптимизируются иначе, чем глобальная область видимости, поэтому создание новых объектов имеет некоторые проблемы, когда вы пытаетесь вызвать их напрямую, если они никаким образом не инициализированы. Я скопирую несколько способов обойти эти проблемы со страницы github
Если вы чувствуете, что использование
exec()
- это не то , с чем вы хотите идти, вы можете подражать поведению, обновив настоящий локальный словарь (не тот, который возвращается locals ()). Я скопирую пример с https://faster-cpython.readthedocs.io/mutable.htmlВывод:
источник
Не думаю, что тебе стоит этого хотеть. Функции, которые могут изменять что-то в своем окружающем контексте, опасны, поскольку этот контекст может быть написан без знания функции.
Вы можете сделать это явным, либо сделав B общедоступным методом, а C - частным методом в классе (вероятно, лучший способ); или используя изменяемый тип, такой как список, и явно передав его в C:
источник
nonlocal
ключевое слово, но вы должны использовать его с большой осторожностью.Вы можете, но вам придется использовать глобальный статус (не очень хорошее решение, как всегда при использовании глобальных переменных, но оно работает):
источник
Я не знаю, есть ли у функции атрибут, который дает значение
__dict__
внешнего пространства функции, когда это внешнее пространство не является глобальным пространством == модуль, что имеет место, когда функция является вложенной функцией, в Python 3.Но в Python 2, насколько мне известно, такого атрибута нет.
Итак, единственные возможности делать то, что вы хотите:
1) использование изменяемого объекта, как говорят другие
2)
результат
.
Nota
У решения Седрика Жюльена есть недостаток:
результат
Глобальный b после выполнения
A()
был изменен, и это может быть нежелательноЭто так, только если в глобальном пространстве имен есть объект с идентификатором b.
источник