我的 Python 项目中经常有需要在模块之间共享的变量。我知道这可以通过函数调用的 args 来完成,但有时,创建一个 global_vars.py 模块并添加需要在那里共享的任何变量会更方便,这就是我经常做的事情。然后可以从任何其他模块导入这些变量,并轻松共享。这通常对我来说效果很好。但有时,一些意想不到的事情会发生。
例如:
我有 3 个文件:
main.py:
from global_vars import var
from mod import modify_variable
print(f"{hex(id(var))} - address of var in main module after import")
modify_variable()
print(f"{hex(id(var))} - address of var in main module after modify_variable() call")
global_vars.py:
var = 'hi'
print(f"{hex(id(var))} - address of var during import")
mod.py: 从 global_vars 导入变量
def modify_variable():
global var
print(f"{hex(id(var))} - address of var before modifying it in modify_variable()")
var = 'hello'
print(f"{hex(id(var))} - address of var after modifying it in modify_variable()")
如果使用 Python3 运行 main.py,您会得到如下所示的输出:
0x7f0f993bb7f0 - address of var during import
0x7f0f993bb7f0 - address of var in main module after import
0x7f0f993bb7f0 - address of var before modifying it in modify_variable()
0x7f0f993bb870 - address of var after modifying it in modify_variable()
0x7f0f993bb7f0 - address of var in main module after modify_variable() call
基本上,在我们调用 modify_variable
之前,一切都会按预期运行。
在 modify_variable
中,var
的地址按照我们的预期开始。
然后我们为其分配一个新字符串。这做了一些事情:
- 它在内存中创建一个全新的字符串
- 它将
var
更改为指向这个新字符串的地址 - 垃圾收集器大概会在某个时候清理旧字符串的地址
0x7f0f993bb7f0 - address of var during import
0x7f0f993bb7f0 - address of var in main module after import
0x7f0f993bb7f0 - address of var before modifying it in modify_variable()
0x7f0f993bb870 - address of var after modifying it in modify_variable()
0x7f0f993bb870 - address of var in main module after modify_variable() call
但事实并非如此。 modify_variable
中的 var
和 main.py 中的 var
现在指向完全不同的地址,并且不能再共享相同的数据。
发生了什么?根据我的阅读,如果我没有在 mod.py
中使用 global var
,我可能会创建一个同名的局部变量全局 var
变量,这可能会导致上述症状,但像我一样使用 global var
可确保我处理的是 global_vars.var
,不是吗?
最佳答案
规范
Python 并没有真正的全局变量。这是 python defines作为全局:
If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.)
还有global
声明的意思是:
It means that the listed identifiers are to be interpreted as globals.
即作为模块级变量。
如果你看看import
是:
- find the module specified in the from clause, loading and initializing it if necessary;
for each of the identifiers specified in the import clauses:
[...]
- [...] a reference to that value is stored in the local namespace, using the name in the as clause if it is present, otherwise using the attribute name
您的案例
因此,global_vars.var
指向地址0x7f0f993bb7f0
,当你将其导入mod
时,它就变成了mod.var
也指向 0x7f0f993bb7f0
。
当你执行global var
时,你告诉Python解析器将var
绑定(bind)到mod.var
,然后使用var = 'hello'
,您使 mod.var
指向 0x7f0f993bb870
。
但是在 main.py
中,var
绑定(bind)到 main.var
,它是由 import
分配的语句到 global_vars.var
,即 0x7f0f993bb7f0
。
做什么
将全局变量实现为单个全局对象的属性:
g.py
:
class Global:
pass
g = Global()
setattr(g, 'var', 'hi')
print(f"{hex(id(g.var))} - address of var during import")
mod.py
:
from g import g
def modify_variable():
print(f"{hex(id(g.var))} - address of var before modifying it in modify_variable()")
g.var = 'hello'
print(f"{hex(id(g.var))} - address of var after modifying it in modify_variable()")
main.py
:
#!/usr/bin/python3.6
from g import g
from mod import modify_variable
print(f"{hex(id(g.var))} - address of var in main module after import")
modify_variable()
print(f"{hex(id(g.var))} - address of var in main module after modify_variable() call")
输出:
0x7ff2a47a1998 - address of var during import
0x7ff2a47a1998 - address of var in main module after import
0x7ff2a47a1998 - address of var before modifying it in modify_variable()
0x7ff2a47ae500 - address of var after modifying it in modify_variable()
0x7ff2a47ae500 - address of var in main module after modify_variable() call
关于python - 关于变量作用域的棘手 Python 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59906128/