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

时间:2020-03-04 11:01:13

标签: python import global-variables

我无法理解为什么在使用import时从另一个模块导入全局变量能按预期进行,但是在使用from x import *时,全局变量似乎不会在其自己的模块中更新< / p>

假设我有2个文件, 一个.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不遵守更新,但是我不知道为什么。

2 个答案:

答案 0 :(得分:1)

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

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

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

与字典的比喻

我们可以使用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'

我们不希望仅仅因为我们重写了two中的值而更新one字典。

您能做什么

只要不通过覆盖变量破坏指针,就可以修改对象。例如,如果x是字典,则可以在字典内部更改一个值,而这两个变量仍将指向同一对象。

或者,您可以像这样将变量附加到函数:

def change(value):
    change.x = value

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

一个更好的答案可能是将两个物品包装在一起,如果它们需要一起旅行:

class Changer:
    x = 'start'

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

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

Changer.x = 'updated'

这可能是最简单的。

答案 1 :(得分:0)

这可能是您在two.py中可以做的最好的事情:

import one
from one import x

def change(value):
    one.change(value)
    global x
    from one import x