我希望我的模块中的一个函数能够访问和更改导入它的脚本的本地命名空间。这将启用这样的功能:
>>> import foo
>>> foo.set_a_to_three()
>>> a
3
>>>
这在Python中是否可行?
答案 0 :(得分:4)
要让模块访问脚本的命名空间,您必须将命名空间传递给该函数。例如:
>>> 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
会更容易。将名称空间传递给其他程序并不是一个好习惯。
答案 1 :(得分:4)
@omz在Slack团队中慷慨地提供了答案:
import inspect
def set_a_to_three():
f = inspect.currentframe().f_back
f.f_globals['a'] = 3
这提供了优于__main__
解决方案的优势,它可以在多个级别的导入中运行,例如a
导入b
导入我的模块foo
,{{ {1}}可以修改foo
的全局变量,而不仅仅是b
&#39} s(我认为)
但是,如果我理解正确,修改本地命名空间会更复杂。正如其他人指出的那样:
当您从另一个函数中调用该函数时,它会中断。然后堆栈中的下一个命名空间是本地的假字典,你无法写入。好吧,你可以,但写作被忽略了。
如果有更可靠的解决方案,我们将非常感激。
答案 2 :(得分:3)
免责声明:此解决方案只能修改全局变量,因此它并不完美。有关优缺点,请参阅Is it good practice to use import __main__
?。
在foo.py中:
import __main__
def set_a_to_three():
__main__.a = 3
__main__
是当前顶级程序的名称。例如,如果您从模块foo
导入bar
,则可以使用名称bar
引用__main__
。如果您从最初从模块foo
导入的bar
导入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"]
答案 3 :(得分:2)
在__main__
中设置很容易,因为我们知道它的名字。
#foo.py
import sys
def set_a_to_three():
sys.modules['__main__'].a = 3