为什么重置Python全局值无效

11 投票
3 回答
1440 浏览
提问于 2025-04-17 18:05

我对Python中的全局变量有点困惑,这里有两段代码

#gl.py

import cli

a = 1    
print "gl 1: %d %d" % (id(a), a)


def reset():
    global a
    a = 7
    print "reset 1: %d %d" % (id(a), a)


if __name__ == '__main__':
    cli.handler(reset)
    print "gl 2: %d %d" % (id(a), a)

这是命令行代码

#cli.py

def handler(func):
    from gl import a
    print "cli 1: %d %d" % (id(a), a)
    func()
    print "cli 2: %d %d" % (id(a), a)

执行的结果是

$ python gl.py
gl 1: 150847672 1
gl 1: 150847672 1
cli 1: 150847672 1
reset 1: 150847600 7
cli 2: 150847672 1    #Why value doesn't change
gl 2: 150847600 7

在这里,我不明白为什么在执行“function reset()”之后,cli.py中的全局变量值没有变化(cli 2: 150847672 1),但回到gl.py时,全局变量的值却发生了变化!!

3 个回答

2

你的 gl 模块被导入了两次,而且是在两个不同的命名空间里。

试试这个:

import sys
print sys.modules['__main__'].a
print sys.modules['gl'].a
2

你在命令行中导入的gl其实是模块对象的一个副本。

如果我们把你的代码改成这样:

#gl.py

import cli
import sys

a = 1    
print "gl 1: %d %d" % (id(a), a)
print "gl id on import: {0}".format(id(sys.modules[__name__]))


def reset():
    global a
    a = 7
    print "gl id in reset: {0}".format(id(sys.modules[__name__]))
    print "reset 1: %d %d" % (id(a), a)

def printa():
    print "gl: %d %d" % (id(a), a)

if __name__ == '__main__':
    cli.handler(reset)
    print "gl id in main: {0}".format(id(sys.modules[__name__]))
    print "gl 2: %d %d" % (id(a), a)

然后

#cli.py

def handler(func):
    #from gl import a
    import gl
    print "gl id in cli: {0}".format(id(gl))
    print "cli 1: %d %d" % (id(gl.a), gl.a)
    func()
    print "cli 2: %d %d" % (id(gl.a), gl.a)
        gl.reset()
        print "cli 3: %d %d" % (id(gl.a), gl.a)

我们得到:

gl 1: 19056568 1
gl id on import: 140075849968728
gl 1: 19056568 1
gl id on import: 20004096
gl id in cli: 20004096
cli 1: 19056568 1
gl id in reset: 140075849968728
reset 1: 19056424 7
cli 2: 19056568 1
gl id in reset: 20004096
reset 1: 19056424 7
cli 3: 19056424 7
gl id in main: 140075849968728
gl 2: 19056424 7

所以当我们运行reset时,我们改变了

a -> 19056568

的引用

a -> 19056424

但这只是在一个gl副本中。另一个副本(在命令行中的那个)仍然保持着旧的引用。如果我们在命令行中运行gl.reset(),那个副本的引用就会改变,这样我们就能在命令行中看到预期的变化。

4

这里缺少两个概念

  • 全局变量是模块之间的全局变量,而不是跨模块的全局变量

参考: http://legacy.python.org/doc/essays/ppt/hp-training/sld036.htm

参考: http://docs.python.org/release/2.4/ref/global.html

  • 变量是以值的形式导入,而不是通过引用导入

参考: https://stackoverflow.com/a/3338357/977038

如果你需要在模块之间共享全局变量,可以参考 如何在模块之间共享全局变量?

撰写回答