Python修改导入脚本命名空间
Modify namespace of importing script in Python
我希望我的模块中有一个函数能够访问和更改导入它的脚本的本地命名空间。这将启用如下功能:
>>> import foo
>>> foo.set_a_to_three()
>>> a
3
>>>
这在 Python 中可行吗?
要让模块访问脚本的命名空间,您必须将命名空间传递给函数。例如:
>>> import foo
>>> foo.set_a_to_three(globals(), locals())
>>> a
3
内部代码如下所示:
def set_a_to_three(globalDict, localDict):
localDict['a'] = 3
旁注:在这种情况下,不需要全局字典,但如果需要修改全局变量,则需要使用全局字典。出于这个原因,我将其包含在此处以使功能可扩展。
但是,如 Eli Sadoff 所说,直接设置 a = 3
会更容易。将命名空间传递给其他程序不是一个好习惯。
Slack 团队 @omz 慷慨地提供了一个答案:
import inspect
def set_a_to_three():
f = inspect.currentframe().f_back
f.f_globals['a'] = 3
这提供了优于 __main__
解决方案的优势,它可以在多个级别的导入中工作,例如,如果 a
导入 b
导入我的模块,foo
, foo
可以修改 b
的全局变量,而不仅仅是 a
的(我认为)
不过,如果我没理解错的话,修改本地命名空间比较复杂。正如其他人指出的那样:
It breaks when you call that function from within another function. Then the next namespace up the stack is a fake dict of locals, which you cannot write to. Well, you can, but writes are ignored.
如果有更可靠的解决方案,将不胜感激。
免责声明:此方案只能修改全局变量,所以并不完美。请参阅 Is it good practice to use import __main__
? 了解优缺点。
在foo.py中:
import __main__
def set_a_to_three():
__main__.a = 3
__main__
是给当前顶层程序起的名字。例如,如果您从模块 bar
导入 foo
,则可以使用名称 __main__
引用 bar
。如果您从 bar
导入 foo
,它最初是从模块 qux
导入的,那么 qux
就是 __main__
,等等
bar -> foo
bar is __main__
qux -> bar -> foo
qux is __main__
如果你真的想修改 bar
中的变量而不是 qux
,例如因为 qux
包含单元测试,你可以使用这样的东西:
import sys
import __main__
if "bar" in sys.modules:
__main__ = sys.modules["bar"]
在__main__
中设置很容易,因为我们知道它的名字。
#foo.py
import sys
def set_a_to_three():
sys.modules['__main__'].a = 3
我希望我的模块中有一个函数能够访问和更改导入它的脚本的本地命名空间。这将启用如下功能:
>>> import foo
>>> foo.set_a_to_three()
>>> a
3
>>>
这在 Python 中可行吗?
要让模块访问脚本的命名空间,您必须将命名空间传递给函数。例如:
>>> import foo
>>> foo.set_a_to_three(globals(), locals())
>>> a
3
内部代码如下所示:
def set_a_to_three(globalDict, localDict):
localDict['a'] = 3
旁注:在这种情况下,不需要全局字典,但如果需要修改全局变量,则需要使用全局字典。出于这个原因,我将其包含在此处以使功能可扩展。
但是,如 Eli Sadoff 所说,直接设置 a = 3
会更容易。将命名空间传递给其他程序不是一个好习惯。
Slack 团队 @omz 慷慨地提供了一个答案:
import inspect
def set_a_to_three():
f = inspect.currentframe().f_back
f.f_globals['a'] = 3
这提供了优于 __main__
解决方案的优势,它可以在多个级别的导入中工作,例如,如果 a
导入 b
导入我的模块,foo
, foo
可以修改 b
的全局变量,而不仅仅是 a
的(我认为)
不过,如果我没理解错的话,修改本地命名空间比较复杂。正如其他人指出的那样:
It breaks when you call that function from within another function. Then the next namespace up the stack is a fake dict of locals, which you cannot write to. Well, you can, but writes are ignored.
如果有更可靠的解决方案,将不胜感激。
免责声明:此方案只能修改全局变量,所以并不完美。请参阅 Is it good practice to use import __main__
? 了解优缺点。
在foo.py中:
import __main__
def set_a_to_three():
__main__.a = 3
__main__
是给当前顶层程序起的名字。例如,如果您从模块 bar
导入 foo
,则可以使用名称 __main__
引用 bar
。如果您从 bar
导入 foo
,它最初是从模块 qux
导入的,那么 qux
就是 __main__
,等等
bar -> foo
bar is __main__
qux -> bar -> foo
qux is __main__
如果你真的想修改 bar
中的变量而不是 qux
,例如因为 qux
包含单元测试,你可以使用这样的东西:
import sys
import __main__
if "bar" in sys.modules:
__main__ = sys.modules["bar"]
在__main__
中设置很容易,因为我们知道它的名字。
#foo.py
import sys
def set_a_to_three():
sys.modules['__main__'].a = 3