Python:在模块和类之间共享全局变量

37 投票
5 回答
35640 浏览
提问于 2025-04-16 01:52

我知道在Python中可以在不同的模块之间共享一个全局变量。不过,我想了解这种共享的范围有多大,以及原因是什么。例如,

global_mod.py

x = None

mid_access_mod.py

from global_mod import *

class delta:
    def __init__(self):
        print x

bot_modif_mod.py

import mid_access_mod
import global_mod

class mew:
    def __init__(self):
        global_mod.x = 5

def main():
    m = mew()
    d = mid_access_mod.delta()

这段代码打印出None,尽管所有模块都在共享全局变量x。为什么会这样呢?看起来在mid_access_mod.py中,x的值是在bot_modif_mod.py的mew()函数给它赋值之前就被使用了。

5 个回答

0

我把例子改成用列表来表示x,并且按照最上面的回答建议使用了列表赋值(x[0] = ..),结果打印出来的还是最开始的值(None)。这证明了“from global_mod import *”是复制的,不管是可变的还是不可变的。

正如评论中提到的,“import global_mod”是有效的,如果在mid_access_mod中使用“print global_mod.x =”。

27

from whatever import * 这个写法在你的代码中不太好,它主要是为了在交互式会话中省事而设计的。简单来说,它会把那个模块里所有的名字都“快照”下来,记录在那一刻的状态。如果你之后改变了这些名字,之前的快照就会过时,可能会引发各种问题。这只是使用这个糟糕的 from ... import * 方式所带来的麻烦的开始。

想听我的建议吗?忘掉这个写法的存在,永远不要再用它。你可以用 import global_mod as m,然后在后面的代码中总是使用带前缀的名字,比如 m.x。在Python中,带前缀的名字要方便和强大得多,比起简单的名字来说,简直没法比。(as m 这个部分是可选的,主要是为了让代码更简洁,或者有时候是为了避免名字冲突;如果你觉得它方便就用,但如果觉得没必要,也不要强迫自己使用)。

39

这个问题发生是因为你使用的是不可变的值(比如整数和None),而导入变量就像是按值传递东西,而不是按引用传递。

如果你把global_mod.x改成一个列表,并且操作它的第一个元素,那就会像你预期的那样工作。

当你使用from global_mod import x时,你在你的模块里创建了一个名字x,它的值和global_mod里的x是一样的。对于函数和类来说,这样做是可以的,因为人们通常不会在后面重新给这些名字赋值。

正如Alex指出的,如果你使用import global_mod,然后用global_mod.x,你就能避免这个问题。你在模块里定义的名字会是global_mod,它总是指向你想要的模块,然后通过属性访问来获取x,就能得到x的最新值。

撰写回答