共享模块中的 Python 全局变量 [duplicate]

Python global variables in shared modules [duplicate]

提问人:John Elion 提问时间:10/9/2023 最后编辑:John Elion 更新时间:10/9/2023 访问量:118

问:

我正在尝试了解跨模块共享的变量的行为。我的印象是,一个模块中的全局变量可以在另一个模块中访问,有时这似乎是发生的事情,但有时并非如此。 (我承认全局变量通常不是正确的工具,但在某些情况下,它们的使用是合适的。

下面是一个代码示例来说明我的困惑:

shared.py

globalvar=0                 # a global scalar variable
globalarray1=[1,2,3]        # a global array modified by .append()
globalarray2=['A','B','C']  # a global array modified by reassignment

def set_globals():
    global globalvar
    global globalarray1
    global globalarray2

    globalvar=1
    globalarray1.append(4)
    globalarray2=['a','b','c']

    print("set_globals: globalvar="+str(globalvar))
    print("set_globals: globalarray1="+str(globalarray1))
    print("set_globals: globalarray2="+str(globalarray2))

module.py

from paas.shared import *

def _main_():
    global globalvar
    global globalarray1
    global globalarray2

    set_globals()

    print("main: globalvar="+str(globalvar))
    print("main: globalarray1="+str(globalarray1))
    print("main: globalarray2="+str(globalarray2))

_main_()

当我运行程序时,我得到以下输出:

set_globals: globalvar=1
set_globals: globalarray1=[1, 2, 3, 4]
set_globals: globalarray2=['a', 'b', 'c']
main: globalvar=0
main: globalarray1=[1, 2, 3, 4]
main: globalarray2=['A', 'B', 'C']

所以

  • 'main' 没有看到共享模块中由 'set_globals' 方法设置的相同标量变量 'globalvar'(赋值 'takek' 并在 'set_globals' 中打印,但 'main' 正在打印其他内容。
  • 它似乎确实看到了相同的“globalarray1”——当 'main' 打印时,可以识别在 set_globals 中修改 globalarray1 的 append(4)。
  • 它没有看到相同的“globalarray2”——set_globals 中分配的变量由 'set_globals' 正确打印,但 'main' 正在打印分配给 globalarray2 的原始值。

有人可以解释一下发生了什么吗?我只看过关于全局变量的相当简单的教程类型文档;如果有描述这里发生的事情的文档,我将不胜感激。

补充说明:这与函数中的局部变量隐藏同名全局变量的方式无关;这是两个不同的变量,具有相同的名称和不同的初始值。导入似乎确实创建了一个具有相同名称的新模块变量,但它以导入模块中同名变量的初始值开头。

全球

评论

4赞 Tom Karzes 10/9/2023
当您这样做时,它会将 from module 的当前值复制到当前命名空间中。如果模块随后在其命名空间中分配给该变量,则它们将不再引用同一对象。但是,如果它只是修改它引用的对象(例如追加到列表),那么它们将继续引用同一个对象。这正是在本地将一个变量分配给另一个变量时的行为方式。例如: 与。。from module import varvarmodulex = 5; y = x; x = 6x = [1, 2, 3]; y = x; x.append(4)
2赞 roganjosh 10/9/2023
实际上,我不确定该欺骗是否真的描述了这里的行为,即使它提到了跨模块的变量
0赞 John Elion 10/9/2023
@TomKarzes这似乎是我所怀疑的:两个模块都有一个“局部”变量,最初指向同一个对象,但赋值似乎只更改了该模块中的变量以指向一个新对象。当对象被破坏性地修改时,指向该对象的每个人都会看到更改。这与函数中的局部变量隐藏全局变量的方式不同。
0赞 John Elion 10/10/2023
这不是函数中全局问题的重复。下面的第一个答案是有效的,是合适的,并且与“函数中的全局变量”问题中的情况非常不同。

答:

-1赞 memyself 10/9/2023 #1

你所观察到的源于 Python 在变量、导入和可变性方面的行为。让我们分解一下:

  1. 共享可变对象(在本例中为列表):
  • globalarray1是一个列表,在 Python 中是一个可变对象。当您这样做时,您正在更改原始列表对象。globalarray1.append(4)
  • 导入 using 时,您正在导入对该列表对象的引用。因此,当您在 中对列表进行突变时,该突变在 module.py 中可见。globalarray1module.pyfrom paas.shared import *shared.py
  1. 重新分配变量:
  • globalarray2=['a','b','c']Inside 将变量重新分配给新的 List 对象。但是,仍然引用原始列表对象。set_globalsmodule.py
  • 对于标量,当您设置 时,您将修改 范围内变量的值。但是,在 中,仍然引用旧值 (0)。globalvarglobalvar=1set_globalsshared.pymodule.pyglobalvar
  1. Python 的导入机制:
  • 当您使用语法时,您将从 into 中导入名称。如果稍后重新绑定其中一个名称(如使用 和 ),则绑定 in 保持不变。from paas.shared import *shared.pymodule.pyshared.pyglobalvarglobalarray2module.py

如何解决此问题并查看一致的行为:

您应该使用显式模块前缀从共享模块访问变量。这样,您始终引用共享模块中变量的最新值。以下是如何更改您的,我们称之为:module.pymodule2.py

import paas.shared as shared

def _main_():
    shared.set_globals()

    print("main: globalvar="+str(shared.globalvar))
    print("main: globalarray1="+str(shared.globalarray1))
    print("main: globalarray2="+str(shared.globalarray2))

_main_()

通过此更改,中的 print 语句将直接引用共享模块的变量版本,并且您将看到 和 之间的行为一致。_main_()set_globals_main_()

现在让我们比较一下输出。这是(从上面未修改):module.py

$ python module.py

   set_globals: globalvar=1
   set_globals: globalarray1=[1, 2, 3, 4]
   set_globals: globalarray2=['a', 'b', 'c']
   main: globalvar=0
   main: globalarray1=[1, 2, 3, 4]
   main: globalarray2=['A', 'B', 'C']

现在使用显式导入的新代码():module2.py

$ python module2.py  
                        
   set_globals: globalvar=1
   set_globals: globalarray1=[1, 2, 3, 4]
   set_globals: globalarray2=['a', 'b', 'c']
   main: globalvar=1
   main: globalarray1=[1, 2, 3, 4]
   main: globalarray2=['a', 'b', 'c']

评论

2赞 slothrop 10/9/2023
stackoverflow.com/help/gpt-policy
0赞 John Elion 10/9/2023
这似乎确实描述了我所看到的。我将探索在 import 语句上使用句柄;如果这可行,我认为这是一个非常完整的答案。
0赞 memyself 10/9/2023
运行修改后的 module.py 时看到的输出是什么?
0赞 John Elion 10/10/2023
这是有效的。