2013-03-25 2 views
10

Мое подозрение в том, что то, что я хочу сделать, не совсем понятно в Python. Вот несколько вложенных функций, которые называют друг друга. (В общем, они не должны быть лексически ограниченные, но нужно динамически вызывать друг друга.)Доступ к переменным функции вызывающего абонента в Python

def outer() : 
    s_outer = "outer\n" 

    def inner() : 
     s_inner = "inner\n" 
     do_something() 

    inner() 

Теперь, когда я звоню do_something() тогда я хотел бы получить доступ к переменным функций вызова дальше callstack, в этом случае 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")) 

работает просто отлично.

Мои два вопроса эти

  1. Есть ли лучший способ решить эту проблему? (Помимо обертывания соответствующих данных в dicts и передачи этих dicts явно на do_something())

  2. Есть ли более элегантный/укороченный способ реализации функции reach()?

Приветствия!

ответ

1

То, что я в конечном итоге делает был

scope = locals() 

и сделать scope доступны из do_something. Таким образом, мне не нужно добираться, но я все равно могу получить доступ к словарю локальных переменных вызывающего. Это похоже на создание самого словаря и передачу его.

4

Нет, и, на мой взгляд, не должно быть элегантного способа реализации reach, так как это вводит новую нестандартную косвенность, которую очень сложно понять, отладить, протестировать и поддерживать. Поскольку мантра Python (пример import this) говорит:

Явный лучше, чем неявный.

Итак, просто передайте аргументы. Вы-из-за-будущего будете очень благодарны вам - с сегодняшнего дня.

+0

Я волновался, что это ответ. Ах хорошо. Независимо от того, что делает функция reach(), существует ли более компактный способ реализации вложенных для/если вообще? – Jens

+0

@Jens Не может придумать ничего, что было бы более читаемым. Вы можете проверить, подходит ли вам просмотр через 'f_back' из' inspect.currentframe() '. – bereal

0

Есть ли лучший способ решить эту проблему?(Помимо обертывания соответствующих данных в dicts и передачи этих dicts явно в do_something())

Передача диктонов явно является лучшим способом.

Что вы предлагаете, звучит очень нетрадиционно. Когда код увеличивается по размеру, вам нужно разбить код на модульную архитектуру с чистыми API-интерфейсами между модулями. Он также должен быть тем, что легко понять, легко объяснить и легко передать другому программисту, чтобы изменить/улучшить/отладить его. То, что вы предлагаете, звучит так: нет чистый API, нетрадиционный, с неочевидным потоком данных. Я подозреваю, что это, вероятно, заставит многих программистов сердиться, когда они это увидели. :)

Другой вариант - сделать функции членами класса с данными, находящимися в экземпляре класса. Это может хорошо работать, если ваша проблема может быть смоделирована как несколько функций, работающих на объекте данных.

+0

Все, что вы говорите, имеет смысл для меня, и обычно я соглашаюсь. Необычно, хотя я изучаю Python в данный момент, и это означает, что я хочу как можно ниже и грязнее. Это не код доставки и только для частного проекта, поэтому я буду единственным сварливым программистом здесь ;-) – Jens

Смежные вопросы