每个模块都有自己的全局变量。 Python 的行为完全符合预期。更新 globalEx1 的 a 以指向其他内容不会影响 globalEx2 的 a 指向的位置。
有多种解决方法,具体取决于您想要什么。
- 在
setvalue() 调用后重新导入a
-
return a 并分配它,例如 a = setvalue()。
-
import globalEx1 并使用 globalEx1.a 而不是 a。 (或使用 import globalEx1 as 和更短的名称。)
- 将
globalEx2 的globals() 作为参数传递给setvalue 并设置其值。
- 将
a 设为可变对象包含您的值,如列表、字典或types.SimpleNamespace,并在setvalue 中对其进行变异。
- 在
setvalue 中使用inspect 从其堆栈帧中获取调用者的全局变量。 (方便,但易碎。)
最后一个选项看起来适合我.. 它会以最少的代码更改完成工作,但我可以使用相同的方式更新多个模块的全局变量吗?或者它只给我调用者的全局变量?
选项 6 实际上是最危险的。调用者本身基本上成为函数的隐藏参数,因此像来自另一个模块的装饰器之类的东西可以在没有警告的情况下破坏它。选项 4 只是使隐藏参数显式,所以它不是那么脆弱。
如果您需要它跨两个以上的模块工作,选项 6 还不够好,因为它只为您提供当前调用堆栈。对于您似乎正在尝试做的事情,选项 3 可能是最可靠的。
选项 1 是如何工作的?我的意思是再次运行 -> “from globalEx1 import *”,因为我有很多变量,比如 'a'。
模块在第一次导入时成为对象,并保存在sys.modules 缓存中,因此再次导入它不会再次执行模块。 from ... import(即使是*)只是从该模块对象中获取属性并将它们添加到本地范围(如果在顶层完成,即在任何定义之外,这是模块全局变量。)
模块对象的__dict__ 基本上是它的全局变量,因此任何改变模块全局变量的函数都会影响生成的模块对象的属性,即使它是在导入模块之后完成的。
我们不能从 python 函数中执行 from 'globalEx1 import *',有什么替代方法吗?
星型语法只允许在顶层使用。但请记住,它只是从模块对象中读取属性。所以你可以得到所有模块属性的字典,比如
return vars(globalEx1)
这将比* 给你更多。默认情况下,它不返回以_ 开头的名称,否则不返回__all__ 中指定的子集。您可以使用字典推导过滤结果字典,甚至.update() 其他模块的全局字典以及结果。
但与其重新实现此过滤逻辑,不如使用 exec 使其成为顶层。那么你得到的唯一奇怪的键是__builtins__
namespace = {}
exec('from globalEx1 import *', namespace)
del namespace['__builtins__']
return namespace
然后你可以globals().update(namespace) 或其他任何东西。
像这样使用exec 可能被认为是不好的形式,但老实说,import * 一开始也是如此。