Чтение родительской области в python

Предположим, у меня есть иерархия функций, я хочу иметь доступ (не изменять!) к родительской области. Вот наглядный пример.

def f():
    a = 2
    b = 1
    def g():
        b = 2
        c = 1
        print globals() #contains a=1 and d=4
        print locals() #contains b=2 and c=1, but no a
        print dict(globals(), **locals()) #contains a=1, d=4 (from the globals), b=2 and c=1 (from g)
        # I want a=2 and b=1 (from f), d=4 (from globals) and no c
    g()
a = 1
d = 4
f()

Могу ли я получить доступ к области действия f из g?


person Andy Hayden    schedule 19.07.2012    source источник
comment
У вас есть пример кода прямо здесь. Вы могли бы просто попробовать.   -  person Waleed Khan    schedule 19.07.2012
comment
Я думаю, это было бы вам интересно: ynniv.com/blog/2007 /08/closes-in-python.html   -  person fuaaark    schedule 19.07.2012
comment
@arxanas Пример кода, который у меня есть, этого не делает, однако он иллюстрирует проблему, см. Строку 10.   -  person Andy Hayden    schedule 19.07.2012
comment
Обратите внимание, что локальные переменные f() также включают функцию g.   -  person Sven Marnach    schedule 19.07.2012


Ответы (1)


В общем, вы не можете в Python. Если ваша реализация Python поддерживает кадры стека (CPython поддерживает), вы можете проверить кадр вызывающей функции с помощью модуля inspect и извлечь локальные переменные, но я сомневаюсь, что это лучшее решение для проблемы, которую вы хотите решить (что бы это ни было) . Вероятно, в вашем дизайне есть какой-то недостаток, если вы думаете, что вам это нужно.

Обратите внимание, что использование inspect позволит вам подняться в стеке вызовов, а не в стеке лексических областей. Если вы вернете g из f(), область действия f исчезнет, ​​поэтому к ней вообще невозможно получить доступ, поскольку она даже не существует.

person Sven Marnach    schedule 19.07.2012
comment
Это из-за соображений безопасности невозможность сделать это? Я нахожу область действия такой тонкой/запутанной, но область действия f, безусловно, все еще существует, когда вы вызываете g из f, так как впоследствии вы возвращаетесь к выполнению f (!) Причина, по которой я думал об этом, заключается в модульное тестирование побочных эффектов... :s - person Andy Hayden; 19.07.2012
comment
@hayden: Нет, это не из соображений безопасности. Как я уже сказал, вы можете подняться по стеку вызовов, если ваша реализация Python поддерживает стековые фреймы — просто сделайте что-то вроде inspect.currentframe().f_back.f_locals, чтобы получить локальные переменные вызывающего фрейма, который в вашем примере будет экземпляром f . Причина, по которой вы не можете получить доступ к переменным из лексической области видимости, заключается в том, что это понятие не имеет смысла. В стеке вызовов может быть несколько экземпляров f, все с разными локалами, или их может не быть вовсе. - person Sven Marnach; 19.07.2012
comment
Причина, по которой вы не должны делать что-то подобное, противоречит сути языка программирования с лексической областью видимости, противопоставленной динамической области видимости (то есть практически любому языку программирования). Подробнее см. en.wikipedia.org/wiki/. - person Sven Marnach; 19.07.2012
comment
Я думаю, что меня здесь смущает то, что g имеет доступ к переменным f (например,)... но мы просто не можем их отобразить. - person Andy Hayden; 19.07.2012
comment
@hayden: g() не имеет доступа к b f, если только вы не используете интроспекцию фрейма стека, потому что он скрыт b g. И как только вы на самом деле закрываете некоторые имена f, они присоединяются к замыканию, так что вы можете получить к ним доступ путем самоанализа. Но ваш код на самом деле не обращается ни к какому имени из f, поэтому он не создаст замыкание. - person Sven Marnach; 19.07.2012
comment
Ах ха! Это было то, чего мне не хватало (что они привязываются только после того, как их ищут). Если бы мы могли перебрать все возможные переменные, мы бы закончили... но мы не знаем, что это такое! :( - person Andy Hayden; 19.07.2012
comment
Если вы определяете f_local_state = locals().keys() в функции f, то, находясь в g, вы можете перебирать область действия f, поскольку вы можете получить доступ к f_local_state в g. - person AmourK; 14.11.2018