2016-09-26 350 views
1

我有一部分使用Python 3.5编写的程序,并且通过测试前两个模块来启动。我设法隔离出现两个全局变量无法理解的原因的其中一个模块中的问题。其中一个全局变量(event_count)仅用于单个函数(grep显示字符串“event_count”没有出现在我的任何* .py文件中的任何其他位置),但变量的值在调用功能。如果我在这个模块中为其他全局变量添加打印语句,它也会在同一时刻恢复为原始值。将event_count移动到另一个模块(将其替换为sensorlogic.event_count,eventcount()并将初始化移至其他模块)会使行为消失,因此我有一个修复但不理解。Python模块中的全局变量自发重置

这里是所有使用event_count,在模块sensoreval代码:

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 

我已经尝试将两个模块修剪成合理大小的东西,但是当我这样做时,问题会持续消失。我会继续努力。由于我以前从未使用过Python 3,并且只有一点Python 2.7的体验,所以我认为我在做一些愚蠢的事情,我只是不知道该怎么做。

我相信我的例子不同于一些已经指出的相关帖子,因为变量event_count是全局唯一的,所以它将是静态的。它仅用于此单一功能。字符串“event_count”不会出现在这个或任何其他模块的其他地方。


许多编辑/重播迭代之后,我有证明发生了什么事一个managably小例子。它涉及总共8行代码的两个模块。第一模块,a.py,是__main__

import b 
c = 0 
if __name__ == '__main__': 
    b.init() 
    print("c =", c) 

第二模块是b.py

import a 
def init(): 
    a.c = 1 

运行a.py产生输出:

c = 0 

我预期c仍然是1从a.c = 1b.py

而且,我试图通过删除a.pyif __name__ == '__main__'进一步降低这一点,但随后的例子不再运行:

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' 

我无法解释,要么,但它很可能是相关的。


以下是Mata的领导,我相信下面的代码显示了正在发生的事情。涉及三个模块。a.py

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) 

b.py

import a 

c.py

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 

运行c.py使__main__是不是在导入周期成果的一部分:

__name__ = a 
__name__ = a 
<function f at 0x000001EA101B7840> 
__name__ = __main__ 
a.f is b.a.f? True 
+0

[在创建它们的函数中使用全局变量]的可能重复(http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-这是他们创造的) – rll

+0

这看起来有点相关:http://stackoverflow.com/q/3536620/4996248 –

+0

无论你是什么样的人,都必须有一条线索,让问题消失。另外奇怪的是,你的输出表示'event_count'实际上并没有增加。 –

回答

1

让我们来看看你的两个模块例如一步一步的。那里的行为是预期的,但最初令人困惑,可能解释了其他情况下发生的情况。

如果运行a作为一个脚本,它不是导入为asys.modules,而是作为__main__。第一条语句是import b,它创建一个空模块对象sys.modules['b']并开始初始化它。

第一行b再次输入a。通常情况下,会找到sys.modules['a']下的模块对象,但在这种情况下,您正在运行a作为脚本,因此最初的导入是以不同的名称进行的。由于此时a的名称为a而不是__main__,因此a.c设置为零,并且不会发生任何其他情况。

现在执行返回到b。它现在创建一个功能init,它将sys.modules['a'].c设置为1。我非常明确地写出了对a模块的引用,因为这是您的差异的根本原因。

一旦b被导入,执行返回到a,但不是sys.modules['a']。下一行c = 0实际上将sys.modules['__main__'].c设置为零。希望你在这一点看到问题。下一行称为b.init,它将sys.modules['a']设置为1。然后按预期打印sys.modules['__main__'],该值为零。

为了验证本次博览会的正确性,尝试添加一个print语句

print(sys.modules['a'].c) 

您将得到1。另外,sys.modules['a'] is sys.modules['__main__']将为False。解决此问题的最简单方法不是在给定模块的导入中初始化其他模块的成员。

您的具体案例记录在这里:http://effbot.org/zone/import-confusion.htm#using-modules-as-scripts

其他资源

你可以在导入系统这里的坚韧不拔的细节更多的信息:https://docs.python.org/3/reference/import.html。这里介绍各种陷阱和进口注意事项:http://python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html