Python模块中的全局变量自发重置

时间:2016-09-26 16:42:18

标签: python python-3.x

我有一个用Python 3.5编写的程序的一部分,并通过测试前两个模块开始。我设法在其中一个模块中隔离了一个问题,在这个模块中,两个全局变量似乎切换回原始值,这是我无法理解的。其中一个全局变量(event_count)仅用于一个函数(grep显示字符串" event_count"不会出现在我的任何* .py文件中的任何其他位置),但是变量的值在函数调用之间发生了变化。如果我在此模块中为其他全局变量添加print语句,它也会在同一时刻恢复为原始值。将event_count移动到另一个模块(用sensorlogic.event_count中的eventcount()替换它并将初始化移动到另一个模块)会使行为消失,所以我有一个修复但没有理解。

以下是模块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"不会出现在此模块或任何其他模块中的任何其他位置。

经过多次编辑/重新运行迭代后,我有一个可管理的小例子来演示正在发生的事情。它涉及两个模块,共有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

我希望ca.c = 1的{​​{1}}仍为{1}}。

此外,我尝试通过从b.py删除if __name__ == '__main__'来进一步减少此操作,但随后示例不再运行:

a.py

我也无法解释,但似乎可能是相关的。

根据Mata的领导,我相信下面的代码显示了正在发生的事情。涉及三个模块。 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'

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__

1 个答案:

答案 0 :(得分:2)

让我们一步一步看看你的双模块示例。这种行为是预期的,但最初令人困惑,可能解释了在其他情况下发生的情况。

如果您将a作为脚本运行,则不会将其a导入sys.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(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