Доступ к переменным функции caller в Python
Мое подозрение в том, что то, что я хочу сделать, не совсем выполнимо чистым способом в Python. Вот несколько вложенных функций, которые называют друг друга. (В общем, они не должны лексически ограничены, но им необходимо динамически звонить друг другу.)
def outer() :
s_outer = "outer\n"
def inner() :
s_inner = "inner\n"
do_something()
inner()
Теперь, когда я вызываю do_something()
, я хотел бы получить доступ к переменным вызывающих функций дальше по стоп-казу, в этом случае s_outer
и s_inner
.
К сожалению, ключевое слово nonlocal
здесь помогает мне, только если я определяю do_something()
внутри функции inner()
. Однако, если я определяю его на том же уровне, что и outer()
, тогда ключевое слово nonlocal
не будет работать.
Однако я хочу вызвать do_something()
из других функций, но всегда выполняю его в соответствующем контексте и получаю доступ к соответствующим областям.
Чувствуя себя непослушным, я написал небольшой аксессуар, который я могу вызвать из do_something()
следующим образом:
def reach(name) :
for f in inspect.stack() :
if name in f[0].f_locals : return f[0].f_locals[name]
return None
а затем
def do_something() :
print( reach("s_outer"), reach("s_inner") )
отлично работает.
Мои два вопроса:
-
Есть ли лучший способ решить эту проблему? (Кроме того, чтобы обернуть соответствующие данные в dicts и передать эти dicts явно на do_something()
)
-
Есть ли более элегантный/укороченный способ реализации функции reach()
?
Ура!
Ответы
Ответ 1
То, что я закончил, было
scope = locals()
и сделать scope
доступным из do_something
. Таким образом, мне не нужно добираться, но я все равно могу получить доступ к словарю локальных переменных вызывающего. Это очень похоже на создание самого словаря и его передачу.
Ответ 2
Нет, и, на мой взгляд, не должно быть изящного способа реализации reach
, поскольку это вводит новую нестандартную косвенность, которую действительно сложно понять, отладить, протестировать и поддерживать. Поскольку мантра Python (try import this
) говорит:
Явный лучше, чем неявный.
Итак, просто передайте аргументы. Вы-из-за-будущего будете очень благодарны вам - с сегодняшнего дня.
Ответ 3
Есть ли лучший способ решить эту проблему? (Помимо обертывания соответствующих данных в dicts и передачи этих dicts явно do_something())
Передача dicts явно является лучшим способом.
То, что вы предлагаете, звучит очень необычно. Когда код увеличивается по размеру, вам нужно разбить код на модульную архитектуру с чистыми API-интерфейсами между модулями. Он также должен быть тем, что легко понять, легко объяснить и легко передать другому программисту, чтобы изменить/улучшить/отладить его. То, что вы предлагаете, похоже на то, что это не чистый API, нетрадиционный, с неочевидным потоком данных. Я подозреваю, что это, вероятно, заставит многих программистов сердиться, когда они это увидели.:)
Другой вариант - сделать функции членами класса с данными, находящимися в экземпляре класса. Это может хорошо работать, если ваша проблема может быть смоделирована как несколько функций, работающих с объектом данных.