导入封闭命名空间时,全局变量的更改会丢失



我正在玩范围和命名空间,我发现了一个奇怪的行为,我不知道如何解释。假设我们有一个名为new_script.py的文件,其中包含

a = 0
def func():
import new_script #import itself
new_script.a += 1
print(new_script.a)
func()
print(a)

执行时打印

1 
1 
2 
0

没想到数字的最后一次打印0.据我了解,它在执行 self-import 语句1打印前两个,递增全局a,然后打印2,因为它再次从函数内部递增全局a,但是为什么最后一次打印是0而不是2

TL;DR:你有两个不同的变量__main__.anew_script.a。你只改变new_script.a.

要通过以下方式追踪它:

a = 0

定义__main__模块中的变量a

def func(): ...

定义__main__模块中的函数func

func()

在模块中调用此函数__main__。在功能中:

import new_script

导入new_script模块,其中:

a = 0
def func(): ...

定义new_script模块中的afunc(new_script.anew_script.func)

func()

从模块调用funcnew_script。在功能中:

import new_script

好吧,我们已经导入了它,所以我们不再导入它

new_script.a += 1
print(new_script.a)

递增new_script.a并打印它(我们的第一个1)。然后

print(a)

new_script模块打印a(又名new_script.a)(我们的第二个1)

new_script完了。 回到__main__中的执行:

new_script.a += 1
print(new_script.a)

第二次递增new_script.a并打印它(我们的2)。

最后:

print(a)

印刷a(又名__main__.a)从未改变过(所以0)

好吧,这导致了一个非常有趣的兔子洞。所以谢谢你。

以下是关键点:

  • 导入不会递归。如果导入一次,它将执行模块级代码,但如果再次导入,则不会再次执行。因此,您只能看到 4 个值。
  • 进口是单例。如果您尝试以下代码:
# singleton_test.py
import singleton_test
def func():
import singleton_test #import itself
print(singleton_test.singleton_test == singleton_test)
func()

它将打印:

True
True
  • 导入的模块单例版本与模块的原始运行版本不同

考虑到这一点,我们可以通过用更多的注释来丰富您的代码,特别是使用包含当前模块名称的__name__,如果当前模块是最初运行的模块,则将__main__该名称:

a = 0
print("start", __name__)
def func():
print("Do import", __name__)
import new_script #import itself
new_script.a += 1
print(new_script.a, "func", __name__)
func()
print(a, "outr", __name__)

这将打印

start __main__
Do import __main__
start new_script
Do import new_script
1 func new_script
1 outr new_script
2 func __main__
0 outr __main__

这很好地表明,鉴于导入的模块是单例(但不是运行的模块),您

在模块内函数
  • 内增加值后,首先在函数中打印 1
  • 然后在导入模块的末尾打印 1
  • 然后在原始运行代码上增加单一实例上的值后打印 2
  • 最后,您为最初运行但尚未触及的未更改的外部模块打印 0。

相关内容

  • 没有找到相关文章

最新更新