从模块导入的全局变量没有更新-为什么?

2022-02-26 00:00:00 python import global-variables

问题描述

我很难理解为什么使用import时从另一个模块导入全局变量会按预期工作,但使用from x import *时全局变量似乎不会在其自己的模块内更新

假设我有2个文件, one.py:

def change(value):
        global x
        x = value

x = "start"

和Two.py:

from one import *
print x
change("updated")
print x

我期望:

start
updated

但是我得到.

start
start

如果我正常导入模块,它会按预期工作

import one
print one.x
one.change("updated")
print one.x

结果.

start
updated

鉴于我不能更改ony.py对全局变量的使用(不是我的错),而two.py应该是一种围绕one.py的包装器*,为了一个顽固的变量,我真的希望避免在two.py中使用one.命名空间。

如果不可能,对正在发生的事情进行新手级别的解释可能会帮助我避免再次陷入这样的困境。我知道one.x正在更新,但是two.x不支持这些更新,但我不知道为什么。


解决方案

您可以将包视为词典。包中的每个函数和变量都作为该字典中的一个键列出,您可以使用globals()查看。

从另一个包导入对象时,您会将对该对象的引用复制到您自己的包中,并使用一个名称(如果import <var> as <name>,通常相同,如果您import <var> as <name>则不同)。

通过设置另一个包中的值,您可以用新值覆盖该包中的键,但您的引用将指向旧的引用。

与DICTS的类比

我们可以用DICT作为类比来演示这个过程:

# Our 'packages'
one = {'x': 'start'}
two = {}

# Equivalent of our import
two['x'] = one['x']   

# Variable updated in `one'
one['x'] = 'updated'

# ... and accessed in `two`
print(two['x'])   # Still 'start'

我们不会因为覆盖了one中的值而期望更新two字典。

您可以为此做些什么

只要不通过覆盖变量而中断指针,就可以修改对象。例如,如果x是字典,您可以更改字典内的值,两个变量仍将指向同一对象。

或者,您也可以将变量附加到函数,如下所示:

def change(value):
    change.x = value

这通过确保我们变异的是同一对象来完成相同的工作。

如果这两个项目需要一起旅行,则更好的答案可能是将这两个项目包装在一个对象中:

class Changer:
    x = 'start'

    @classmethod
    def change(cls, value):
        cls.x = value

但是,此时我们可以将该值直接修改为属性:

Changer.x = 'updated'

哪个可能是最简单的。

相关文章