目录
1 单个模块内global
总结: global a表示a为本py模块内均可读、局部(仅本函数内,本函数内部调用的其他函数不包括在内)可写。(这里读与写是个人理解的方式,并不代表python的真正机制,只是好记)
1. 1 先不global的话的情况是:可读但不可写
# foo.py
# 代码1
a = 3
def f():
b = a + 1
print(b)
if __name__ == '__main__':
f()
结果是4,表明可以读到a
# foo.py
# 代码2
a = 3
def f():
a = a + 1
print(b)
if __name__ == '__main__':
f()
结果报错,这里就表示不可写。但是仍有个问题:
1.1.1 python语句左右读的问题(未解决)
# foo.py
# 代码3
import dis
a = 3
def f():
b = a + 1
print(a)
if __name__ == '__main__':
print(dis.dis(f))
dis函数式可以看到cpu的运行过程,结果是:
8 0 LOAD_GLOBAL 0 (a)
2 LOAD_CONST 1 (1)
4 BINARY_ADD
6 STORE_FAST 0 (b)
9 8 LOAD_GLOBAL 1 (print)
10 LOAD_GLOBAL 0 (a)
12 CALL_FUNCTION 1
14 POP_TOP
16 LOAD_CONST 0 (None)
18 RETURN_VALUE
None
这里直接看每一行表示运行的步骤,首先导入的是全局变量a。可以看出这里把a看成的是全局变量,是可以读到的。接下来看一下a = a + 1会怎么样:
# foo.py
# 代码4
import dis
a = 3
def f():
a = a + 1
print(a)
if __name__ == '__main__':
print(dis.dis(f))
8 0 LOAD_FAST 0 (a)
2 LOAD_CONST 1 (1)
4 BINARY_ADD
6 STORE_FAST 0 (a)
9 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (a)
12 CALL_FUNCTION 1
14 POP_TOP
16 LOAD_CONST 0 (None)
18 RETURN_VALUE
None
这里是LOAD_FAST,表示是载入局部变量,所以没有读到,这里不太懂python为什么同样是从右往左但是会有不同的变量区域读法。这里并不是写出现问题,而是读不到了。(但是可以记为不可写,就不会出现a+=1的问题)。应该是有机制先读了左边,我猜的。还有问题:
1.1.2 python语句上下读的问题(未解决)
按说,python是一行一行运行的吧?将代码3的b = a + 1下一行添一句a = b,按说应该出错在a = b这一行:
# foo.py
# 代码5
import dis
a = 3
def f():
b = a + 1
a = b
print(a)
if __name__ == '__main__':
f()
结果:
Traceback (most recent call last):
File "/Users/tanghui/Documents/python就业班/一些草稿纸/foo.py", line 15, in <module>
f()
File "/Users/tanghui/Documents/python就业班/一些草稿纸/foo.py", line 8, in f
b = a + 1
UnboundLocalError: local variable 'a' referenced before assignment
表示出错在b = a + 1,此时a又读不到了。如果用dis函数看一下,又发现python又开始load_fast,当然load不到啊。。不知道为啥子。
1.2 global之后:全局可读,局部可写
1.2.1 全局可读
表明你在函数f中改了之后,函数g中可以读到这个修改(外部也可以,全局都可以读):
# foo.py
# 代码6
a = 3
def f():
global a
a += 1
print(a) # 4
def g():
print(a) # 4
if __name__ == '__main__':
f()
g()
1.2.2 局部可写
如果先将a在全局定义好,然后在函数内部global它:
# foo.py
# 代码7
a = 3 # 外部定义
def f():
global a
a += 1
print(a) # 4
if __name__ == '__main__':
f()
这下可以修改了,但是别的函数内还是不能修改:
# foo.py
# 代码8
a = 3 # 外部定义
def f():
global a
a += 1
print(a) # 4
def g():
a += 1 # 报错 UnboundLocalError: local variable 'a' referenced before assignment
print(a)
if __name__ == '__main__':
f()
g()
如果在f内调用g来修改,也还是不行:
# foo.py
# 代码8
a = 3 # 外部定义
def f():
global a
g()
def g():
a += 1 # 还是报错 UnboundLocalError: local variable 'a' referenced before assignment
print(a)
if __name__ == '__main__':
f()
所以这里的局部可改是仅本函数内,本函数内部调用的其他函数仍不可改。
2 多个模块内的global

得到的结果是 3
接下来把左边程序的a = 3 拿走,运行

结果是报错:a未定义。
所以我们能看到两个模块的global是不互通的,读的层面就不互通,也不会这个模块找不到就到别的模块找,更别说写。所以我说’全局可读‘的’全局‘表自个儿的模块内可读。
可以通过内置函数__globals__来看一下这个为什么不互通
3 __globals__
这个函数看到全局(本模块)可读的量!不一定可写,可写是要看区域的。
# foo.py
# 代码9
a = 3
def f():
global a
a += 1
if __name__ == '__main__':
# f() # 没运行
print(f.__globals__.keys())
print(f.__globals__['a'])
输出结果是:
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'dis', 'a', 'f'])
3
输出结果里有a,因为f()没运行,所以看到的是外部的a = 3
# foo.py
# 代码10
a = 3
def f():
global a
a += 1
if __name__ == '__main__':
f()
print(f.__globals__.keys())
print(f.__globals__['a'])
输出结果是:
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'dis', 'a', 'f'])
4
输出的结果有a,是运行了f函数之后,a是4了。至于这个为什么是f.__globals__这个无所谓,如果还有个g函数,写g.__globals__得到的结果是一样的,因为打印的都是全局可读的量。
两个模块里的global的(读写)不通的,可以用查看两个模块的__globals__(这个函数的结果只表示可读的量)来看:

输出的结果表明f只能打印f里的__globals__的a,而右边函数也有自己的__globals__的a,他俩是不互通的。所以也能解释2里面的问题。
4 多进程
其实这一连串的问题的开始就是我看了好几家的视频教学,这里有个问题感觉没有解释清楚,就是多进程下不可变变量的id没有变的问题。这里两个问题,一,进程间为啥全局变量不互通;二,既然不互通为啥指向同一个内存。
问题的一个描述:

4.1 进程间全局变量不互通的原因
多进程,会多一份资源,并且不互通,这里我老想不通为啥会这样,其实现在我知道了就和上面的两个模块的情况一样!两边拿的__globals__是不同的。所以互不影响,你改了我看不到我改了你看不到。所以多进程就相当于多模块,本来一个py一个模块,现在开了多进程表示多个模块在一个py里,运行py,进程管理器会看到两个.py。所以这里表面的纠结解开了。
4.2 不同进程里的a指向同一地址的原因
一个测试:

没动之前指向同一个id,是因为python对-5~256内的int数据以及所有str数据,都泡在一个池子里,都会指向同一个
In [1]: a = 4
In [2]: b = 4
In [3]: id(a)
Out[3]: 4389426416
In [4]: id(4)
Out[4]: 4389426416
In [5]: a = "asdfghjklzxcvbnm"
In [6]: b = "asdfghjklzxcvbnm"
In [7]: id(a)
Out[7]: 4427009360
In [8]: id(b)
Out[8]: 4427009360
这和那个global是两码事,别放一起想就好了,这是数据的存储机制,节约内存的,与使用上无关。
over
本文详细探讨了Python中的全局变量、`global`关键字的作用,以及在多进程中的行为。在单个模块内,未声明`global`时全局变量可读但不可写,声明后则全局可读,局部可写。多个模块间的全局变量不互通,每个模块有自己的作用域。多进程中,全局变量由于进程隔离而不互通,即使ID相同,也是各自独立的内存副本。

950

被折叠的 条评论
为什么被折叠?



