总结: global a
表示a为本py模块内均可读、局部(仅本函数内,本函数内部调用的其他函数不包括在内)可写。(这里读与写是个人理解的方式,并不代表python的真正机制,只是好记)
# 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()
结果报错,这里就表示不可写。但是仍有个问题:
# 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的问题)。应该是有机制先读了左边,我猜的。还有问题:
按说,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不到啊。。不知道为啥子。
表明你在函数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()
如果先将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()
所以这里的局部可改是仅本函数内,本函数内部调用的其他函数仍不可改。
得到的结果是 3
接下来把左边程序的a = 3 拿走,运行
结果是报错:a未定义。
所以我们能看到两个模块的global是不互通的,读的层面就不互通,也不会这个模块找不到就到别的模块找,更别说写。所以我说’全局可读‘的’全局‘表自个儿的模块内可读。
可以通过内置函数__globals__
来看一下这个为什么不互通
__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里面的问题。
其实这一连串的问题的开始就是我看了好几家的视频教学,这里有个问题感觉没有解释清楚,就是多进程下不可变变量的id没有变的问题。这里两个问题,一,进程间为啥全局变量不互通;二,既然不互通为啥指向同一个内存。
问题的一个描述:
多进程,会多一份资源,并且不互通,这里我老想不通为啥会这样,其实现在我知道了就和上面的两个模块的情况一样!两边拿的__globals__
是不同的。所以互不影响,你改了我看不到我改了你看不到。所以多进程就相当于多模块,本来一个py一个模块,现在开了多进程表示多个模块在一个py里,运行py,进程管理器会看到两个.py。所以这里表面的纠结解开了。
一个测试:
没动之前指向同一个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