python 如何评估模块执行?

How does python evaluate Module execution?

我在同一目录中有两个文件,一个包含我的程序内容 poker.py,另一个包含测试用例 poker_test.py

poker_test.py 中,我对 运行 测试用例执行以下命令:

import unittest
import poker


class PokerTest(unittest.TestCase):
      (...)

然后在 poker.py 结束时我正在开发我有以下命令:

if __name__ == "__main__":
    #imports Test case and unittest
    from poker_test import *
    unittest.main() 

一切正常(目前)并且此设置非常适合迭代开发。我的问题是,当我 运行 时 python 如何评估 poker.py,因为 poker_test.py 取决于 poker.py,反之亦然?

我有一个大概的想法,但想知道 "official" 答案是什么。

谢谢, -M

避免像您在此处创建的那样的循环依赖关系总是最合理的。然而你很幸运,因为 from poker_test import * 出现在 poker.py 的最后,也就是说,在后者定义了它定义的所有内容之后,它可以被循环依赖 poker_test.py.

然而,虽然这恰好适用于当前 Python 版本,但语言规范不能保证。为了solidity,打破循环依赖,例如如下:

  • if __name__ 检查之前移动 poker.py 的所有 "substantial" 内容,例如 _poker.py
  • poker.py中,只做from _poker import *
  • poker_test.py 中,而不是 import poker,使用 import _poker as poker

这样,您的依赖关系图就变成了非循环的,因此您的代码将在 Python 的任何正确版本中按预期工作,包括假设的未来版本:-)。

至于你是否应该这样做,正如亚历克斯所说,不惜一切代价避免它。周期性进口是一种罪恶状态。

除此之外,看看发生了什么很有趣(大致 - 模块导入机制看起来是 an area that gets tweaked from version to version in Python。我的主要来源是 Python 3.4.2 文档导入系统)

poker_test.py内的行:

import poker

执行后,系统首先检查模块是否已经加载。加载的模块位于名为 sys.modules.

的字典中
  • 如果正在导入的模块已经在 sys.modules 中,则 poker_test.py 中对 poker 的任何引用都指向该命名空间。 (请注意,在循环导入的情况下,模块可能已经添加到 sys.modules,但命名空间的填充可能尚未完全结束。该模块的执行可能会在下面的行暂停import this_or_that_other_module)
  • 如果模块不存在,则系统创建一个新的命名空间,将其添加到 sys.modules,查找与 poker 模块关联的代码(在本例中,living in poker.py) 并开始执行它,将所有变量放入新创建的命名空间中。

所以你会认为 poker.py 获得了 运行 一次,而 poker_test.py 获得了 运行 一次并且已经注意到 poker 是一个加载的模块,所以导入到此结束。除了...

当一个模块是 运行 作为原始脚本时,它在 sys.modules 中被注册为 __main__,而不是它的实际名称。

所以poker.py将被称为__main__模块,结果,当poker_test尝试运行宁import poker时,它可以在 sys.modules 下找不到 pokerpoker 加载两次,一次作为 __main__,另一次作为 poker。循环导入是不受欢迎的,但是 __main__ 模块的循环导入是完全谴责的,因为创建两个相同的(ish)命名空间的问题以及可能导致的潜在奇怪错误。

您的代码中还有两个问题。

1) from poker_test import *

因为你正在做一个 import *,而不是将所有从 poker_test 创建的变量放在它自己的命名空间中,它被扔进 __main__ 命名空间。

2) if __name__=='__main__':

因为如果模块是正在执行的主脚本,您只是从 poker_test 导入,所以当 pokerpoker_test。所以你的代码在概念上并不是真正的循环。 poker as __main__ imports poker_test which imports poker and stop there。简单!

...所以我们不要进行循环导入。

一些参考 material:

Official Python 3.4.2 docs on the import system

2008 comp.lang.python discussion on cyclical imports