Как изменить локальное пространство имен в python

Как изменить локальное пространство имен функции в python? Я знаю, что locals () возвращает локальное пространство имен функции при вызове внутри него, но я хочу сделать что-то вроде этого (у меня есть причина, по которой я хочу сделать это, когда g не доступен для f, но это быстрее дать тривиальный, глупый пример, иллюстрирующий проблему):

def g(): pass def f(): g() f.add_to_locals({'g':g}) 

  • Python: NameError: глобальное имя foobar не определено
  • inspect.getmembers () vs __dict __. items () vs dir ()
  • Может кто-нибудь объяснить __all__ в Python?
  • Python: Почему «из <module> import *» запрещается?
  • Почему модули импортируются как _ <имя> в другом модуле?
  • Как сообщить lxml.etree.tostring (element) не писать пространства имен в python?
  • Пространство имен по умолчанию Python ElementTree?
  • Что такое пространства имен Python?
  • Может кто-нибудь объяснить __all__ в Python?
  • Локальные функции в Python
  • Как использовать __init__.py в (под) модули для определения пространств имен?
  • RDFLib: префиксы пространства имен в XML-сериализации
  • 7 Solutions collect form web for “Как изменить локальное пространство имен в python”

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

    Один из вариантов – просто ввести вашу функцию в пространство имен модуля функции. Это будет работать, но будет влиять на каждую функцию в этом модуле, которая обращается к переменной, а не только к одной функции.

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

     import new f = new.function(f.func_code, {'g': my_g_function}, f.func_name, f.func_defaults, f.func_closure) 

    f теперь будет indentical, за исключением того, что он будет искать globals в предоставленном dict. Обратите внимание, что это перепроверяет все глобальное пространство имен – если там есть переменные, которые ищут, убедитесь, что вы их тоже предоставили. Это также довольно хаки, хотя и может не работать на версиях python, кроме cpython.

    Поскольку функция не вызывается, она не имеет «локального» фрейма стека. Самое простое решение – использовать глобальный контекст:

     handler = None def f(): handler() def g(): pass handler = g 

    Или вы можете установить g на объект функции:

     fg = g 

    Но я не уверен, как вы можете получить объект функции из самой функции. Если бы это был метод, вы бы использовали self .

    Почему бы вам просто не добавить аргумент к f() и передать ссылку на g() ?

     def g(): pass def f(func): func() f(g) 

    Я думаю, вы могли бы решить проблему, решив ее из совершенно другой точки.
    Функции – это объект с их словарями; поэтому вы можете добавить g в f и использовать его:

     def g(): print "g" def f(): fg() fg = g 

    Я предполагаю, что вы хотите это сделать, потому что функция f определяется не вами, а каким-то другим модулем. Поэтому вы хотите изменить способ работы f (). В частности, вы хотите изменить то, что вызывается при вызове g.

    Поэтому я предлагаю следующее:

     import thirdpartypackage def mynewg(): pass thirdpartypackage.g = mynewg 

    Это изменит глобальный g для модуля thirdpartypackage. Поэтому, когда вызывается thirdpartypackage.f (), он будет вызывать mynewg () вместо g ().

    Если это не решит его, возможно, g () фактически импортируется из f () или somthing. Тогда решение таково:

     import thirdpartypackage def mynewg(): pass deg mynewf(): mynewg() thirdpartypackage.f = mynewf 

    То есть, вы полностью переопределяете f () с измененной версией, которая делает то, что вы хотите.

    Функция, которая не выполняется, не имеет локалей; локальный контекст создается при запуске функции и уничтожается при выходе из него, поэтому нет «локального пространства имен» для изменения из-за пределов функции.

    Вы можете сделать что-то вроде этого:

     def f(): g = [1] def func(): print g[0] return func, g f, val = f() f() val[0] = 2 f() 

    Это использует массив для моделирования ссылки.

    Это похоже на работу

     def add_to_locals(l): l['newlocal'] = 1 add_to_locals(locals()) assert newlocal 
    Python - лучший язык программирования в мире.