Python模块中的全局变量会自动重置
我有一个用Python 3.5编写的程序的一部分,从测试前两个模块开始。我设法隔离了其中一个模块中的一个问题,其中两个全局变量似乎在毫无原因地切换回其原始值。其中一个全局变量(Python模块中的全局变量会自动重置,python,python-3.x,Python,Python 3.x,我有一个用Python 3.5编写的程序的一部分,从测试前两个模块开始。我设法隔离了其中一个模块中的一个问题,其中两个全局变量似乎在毫无原因地切换回其原始值。其中一个全局变量(event\u count)仅在单个函数中使用(grep显示字符串“event\u count”不会出现在我的*.py文件中的任何其他地方),但变量的值在调用函数之间会发生变化。如果我为这个模块中的另一个全局变量添加print语句,它也会在同一时刻恢复为其原始值。将event\u count移动到另一个模块(将其替换为se
event\u count
)仅在单个函数中使用(grep显示字符串“event\u count”不会出现在我的*.py文件中的任何其他地方),但变量的值在调用函数之间会发生变化。如果我为这个模块中的另一个全局变量添加print语句,它也会在同一时刻恢复为其原始值。将event\u count
移动到另一个模块(将其替换为sensorlogic.event\u count
ineventcount()
中的event\u count
并将初始化移动到另一个模块)会使该行为消失,因此我有一个解决方案,但无法理解
以下是模块传感器评估
中使用事件计数的所有代码:
event_count = 0
def eventcount(increment):
global event_count
print("entering eventcount, increment =", increment,
", event_count =", event_count)
event_count += increment
print("leaving eventcount, event_count =", event_count)
return event_count
如果我运行以下代码段:
e.setvalue(1)
print("I am at marker #1")
eventcount(0)
(在e.setvalue()
中的最后一个操作是调用eventcount(0)
)它生成以下输出:
entering eventcount, increment = 0 , event_count = 4
leaving eventcount, event_count = 4
I am at marker #1
entering eventcount, increment = 0 , event_count = 0
leaving eventcount, event_count = 0
我曾尝试将这两个模块缩减到合理的大小,但当我这样做时,问题就一直在消失。我会继续努力的。因为我以前从未使用过Python3,并且只有一点Python2.7的经验,所以我假设我在做一些愚蠢的事情,我只是不知道是什么
我相信我的例子不同于一些相关的帖子,因为变量event\u count
是全局变量,所以它是静态的。它仅用于此单一功能。字符串“event_count”不会出现在此模块或任何其他模块中的任何其他位置
在多次编辑/重新运行迭代之后,我有一个可管理的小示例来演示正在发生的事情。它涉及两个模块,共8行代码。第一个模块,a.py
,是\uuuu main\uuuu
:
import b
c = 0
if __name__ == '__main__':
b.init()
print("c =", c)
第二个模块是b.py
:
import a
def init():
a.c = 1
print("__name__ =", __name__)
import b
print("__name__ =", __name__)
def f(): pass
print(f)
if __name__ == '__main__':
print("f is b.a.f?", f is b.a.f)
import a
import a
import b
print("__name__ =", __name__)
print("a.f is b.a.f?", a.f is b.a.f)
运行a.py
生成输出:
c = 0
我希望b.py中a.c=1
的c
仍然是1
此外,我试图通过从a.py
中删除if uuuu name\uuuu=='\uuuu main\uuuu'
来进一步减少这种情况,但该示例不再运行:
Traceback (most recent call last):
File "...\a.py", line 1, in <module>
import b
File "...\b.py", line 1, in <module>
import a
File "...\a.py", line 3, in <module>
b.init()
AttributeError: module 'b' has no attribute 'init'
b.py
:
import a
def init():
a.c = 1
print("__name__ =", __name__)
import b
print("__name__ =", __name__)
def f(): pass
print(f)
if __name__ == '__main__':
print("f is b.a.f?", f is b.a.f)
import a
import a
import b
print("__name__ =", __name__)
print("a.f is b.a.f?", a.f is b.a.f)
c.py
:
import a
def init():
a.c = 1
print("__name__ =", __name__)
import b
print("__name__ =", __name__)
def f(): pass
print(f)
if __name__ == '__main__':
print("f is b.a.f?", f is b.a.f)
import a
import a
import b
print("__name__ =", __name__)
print("a.f is b.a.f?", a.f is b.a.f)
您可以通过运行a.py
查看问题,并给出结果:
__name__ = __main__
__name__ = a
__name__ = a
<function f at 0x0000021A4A947840>
__name__ = __main__
<function f at 0x0000021A484E0400>
f is b.a.f? False
让我们一步一步地看一下您的两个模块示例。那里的行为是意料之中的,但一开始令人困惑,并且可能很好地解释了其他情况下的情况
如果将a
作为脚本运行,则不会将其作为a
导入sys.modules
,而是作为\uuuu main\uuu
导入。第一条语句是import b
,它创建一个空的模块对象sys.modules['b']
,并开始初始化它
b
的第一行再次导入a
。通常,会在sys.modules['a']
下找到一个模块对象,但在本例中,您是以脚本的形式运行a
,因此初始导入是以不同的名称进行的。由于a
的名称是a
而不是\uuuuu main\uuuuu
,因此a.c
被设置为零,其他情况不发生
现在执行返回到b
。它现在创建一个函数init
,该函数将sys.modules['a'].c
设置为一。我非常明确地写下了对a
模块的引用,因为这是造成差异的根本原因
导入b
后,执行返回到a
,而不是sys.modules['a']
。下一行,c=0
实际上将sys.modules['''uuuuu'main.'].c
设置为零。希望你现在能看到问题所在。下一行调用b.init
,它将sys.modules['a']
设置为一。然后打印sys.modules[''\uuuuu main\uuuu']
,如预期的那样,它是零
要验证此说明的正确性,请尝试添加打印语句
print(sys.modules['a'].c)
您将获得1
。另外,sys.modules['a']是sys.modules[''''main']
将是False
。解决这个问题的最简单方法是不要在给定模块的导入中初始化其他模块的成员
您的具体案例记录在此处:
其他资源
您可以在此处获得有关导入系统的详细信息:。这里介绍了各种进口陷阱和注意事项:。这一点的可能重复看起来很相关:无论是什么样的修剪,都必须有一个线索,才能消除问题。同样奇怪的是,您的输出显示event\u count
实际上没有增加。我敢打赌,如果您运行eventcount(4)
,然后运行eventcount(0)
,您将得到预期的结果。因此,错误必须出现在e.setvalue()
Quote中:“e.setvalue()中的最后一个操作是调用eventcount(0)”。这有什么意义?