python跨文件全局变量问题
2019年02月24日

问题发现

首先是一个使用全局变量的一个文件:

#a.py
import b
g = 10
def func1():
    global g
    print(g)
    g += 1
if __name__ =='__main__' :
    func1()
    print(g)
    b.func2()

不看最后b.func2,很明显结果是

10

11

此时全局变量g已经变成11了。

#b.py
import a
def func2():
    bg = a.g
    print(bg)

然而当调用b.func2时,打印的数字是10,也就是说a的全局变量的改变并没有传递给b。

问题分析

python内置了id函数,每个地址都有独一无二的id,所以看id就可以很明白的知道数字是多少

#===================a.py======================
import b
g = 10
def func1():
    global g
    print(g)
    g += 1
if __name__ =='__main__' :
    print("id g:",id(g))
    print("id 10:",id(10))
    func1()
    print(g)
    print("id g:",id(g))
    print("id g:",id(11))
    b.func2()
   
#==================b.py====================
import a
def func2():
    bg = a.g
    print("id a.g:",id(a.g))
    print("id bg:",id(bg))
    print(bg)

运行结果为

id g: 140733566137456
id 10: 140733566137456
10
11
id g: 140733566137488
id g: 140733566137488
id a.g: 140733566137456
id bg: 140733566137456
10

可以发现,当最初g为10时,g和10的id一样,g+1变为11时,id也一样。而当传递到b时,a.g的id就和10的id一样,并且没有随着a中的全局变量的改变而改变。

解决方案

由于本质需求就是想要跨文件共享全局变量,所以比较好的办法是用第三个文件作为全局变量库,用于存储需要共享的全局变量。为了安全起见,可以考虑采用两个函数接口来获取/修改全局变量,而不是直接访问。

#==============a.py================================================
from global_val import global_get,global_set
import b
def func1():
    ag = global_get('g')
    print('ag:',ag)
    ag += 1
    global_set('g',ag)
if __name__ =='__main__' :
    func1()
    print(global_get('g'))
    b.func2()
    print(global_get('g'))
    
#==============b.py================================================
from global_val import global_get,global_set
def func2():
    bg = global_get('g')
    print('bg:',bg)
    bg += 1
    global_set('g',bg)
    
#==============global_val.py====================================
g_dict = {
    'g':10
    }
def global_get(key):
    try:
        return g_dict[key]
    except KeyError:
        return False
def global_set(key, value):
    try:
        g_dict[key] = value
    except KeyError:
        return False

运行结果为

ag: 10
11
bg: 11
12

Problem solved.

--