[英]Tricky Python question about variable scope
I often have variables in my Python projects that I need to share between modules.我的 Python 项目中经常有需要在模块之间共享的变量。 I know this can be done with args to function calls, but sometimes, it's more convenient to create a single global_vars.py module, and add any variables that need to be shared there, which is what I often end up doing.
我知道这可以通过 args 来完成函数调用,但有时,创建一个 global_vars.py 模块更方便,并添加需要在那里共享的任何变量,这是我经常最终做的。 These variables can then be imported from any other module, and easily shared.
然后可以从任何其他模块导入这些变量,并轻松共享。 This generally works fine for me.
这通常对我有用。 Sometimes though, some unexpected stuff happens.
但是,有时会发生一些意想不到的事情。
Ex:前任:
I have 3 files:我有3个文件:
main.py:主要.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: global_vars.py:
var = 'hi'
print(f"{hex(id(var))} - address of var during import")
mod.py: from global_vars import var mod.py: from global_vars import var
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()")
If you run main.py with Python3, you get output that looks like this:如果您使用 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
Basically, everything behaves as expected until we call modify_variable
.基本上,一切都按预期运行,直到我们调用
modify_variable
。 Within modify_variable
, the address of var
starts out as we expect.在
modify_variable
, var
的地址按照我们的预期开始。 Then we assign a new string to it.然后我们为其分配一个新字符串。 This does a few things:
这做了几件事:
var
to point to the address of this new stringvar
更改为指向这个新字符串的地址Given this, I would expect that the last check of the address of var
would also point to the address of the new string.鉴于此,我希望最后一次检查
var
的地址也指向新字符串的地址。 Therefore, I would expect the result to look like this:因此,我希望结果如下所示:
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
but it doesn't.但事实并非如此。
var
within modify_variable
, and var
within main.py now point to completely different addresses, and can no longer share the same data. modify_variable
var
和modify_variable
var
现在指向完全不同的地址,并且不能再共享相同的数据。
What happened?发生了什么? From what I've read, if I hadn't used
global var
in mod.py
, it was possible that I would have created a local variable with the same name as the global var
variable, which could cause the symptoms above, but using global var
as I do ensures I'm dealing with global_vars.var
, doesn't it?从我读到的内容来看,如果我没有在
mod.py
使用global var
,我可能会创建一个与 global var
变量同名的局部变量,这可能会导致上述症状,但使用我所做的global var
确保我正在处理global_vars.var
,不是吗?
Python doesn't really have global variables. Python 并没有真正的全局变量。 Here's what python defines as global:
这是python 定义为全局的内容:
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.)
(模块代码块的变量是局部的和全局的。)
And the global
statement means: global
声明意味着:
It means that the listed identifiers are to be interpreted as globals.
这意味着列出的标识符将被解释为全局变量。
ie as module-level variables.即作为模块级变量。
If you look at what import
does:如果您查看
import
作用:
- find the module specified in the from clause, loading and initializing it if necessary;
找到 from 子句中指定的模块,必要时加载和初始化它;
for each of the identifiers specified in the import clauses:
对于 import 子句中指定的每个标识符:
[...]
[...]
- [...] 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
[...] 对该值的引用存储在本地命名空间中,如果存在则使用 as 子句中的名称,否则使用属性名称
So, global_vars.var
points to address 0x7f0f993bb7f0
, and when you import it to mod
, it becomes mod.var
which also points to 0x7f0f993bb7f0
.所以,
global_vars.var
指向地址0x7f0f993bb7f0
,当你将它导入mod
,它变成mod.var
,它也指向0x7f0f993bb7f0
。
When you do global var
you tell the Python parser to bind var
to mod.var
, and then with var = 'hello'
, you make mod.var
point to 0x7f0f993bb870
.当您执行
global var
您告诉 Python 解析器将var
绑定到mod.var
,然后使用var = 'hello'
,您使mod.var
指向0x7f0f993bb870
。
But in main.py
, var
binds to main.var
, which was assigned by the import
statement to global_vars.var
, namely 0x7f0f993bb7f0
.但是在
main.py
, var
绑定到main.var
,它由import
语句分配给global_vars.var
,即0x7f0f993bb7f0
。
Implement globals as attributes of a single global object:将全局变量实现为单个全局对象的属性:
g.py
: g.py
:
class Global:
pass
g = Global()
setattr(g, 'var', 'hi')
print(f"{hex(id(g.var))} - address of var during import")
mod.py
: 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
: 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")
Output:输出:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.