python如何评估模块执行?

时间:2015-01-13 22:21:26

标签: python unit-testing

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

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

import unittest
import poker


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

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

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

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

我有一个粗略的想法,但想知道"官方"答案是。

谢谢, -M

2 个答案:

答案 0 :(得分:4)

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

除此之外,看一下发生的事情很有意思(粗略地说 - 看起来模块导入机制是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中对poker_test.py的任何引用都只指向该命名空间。 (请注意,在循环导入的情况下,模块可能已经添加到sys.modules,但是命名空间的填充可能还没有完全结束。该模块的执行暂时可能会暂停import this_or_that_other_module
  • 如果模块不在那里,那么系统会创建一个新的命名空间,将其添加到sys.modules,查找与poker模块关联的代码(在这种情况下,生活在{ {1}})并开始执行它,将所有变量放在新创建的命名空间中。

因此,您认为poker.py运行一次,poker.py运行一次并且已经注意到poker_test.py是一个已加载的模块,因此导入结束。除了...

当模块作为原始脚本运行时,它会在poker中注册为__main__,而不是其实际名称。

所以sys.modules将被称为poker.py模块,因此,当__main__尝试运行poker_test时,它无法找到import poker 1 {}在poker下。 sys.modules 加载两次,一次加载为poker,另一次加载为__main__。周期性的导入是不受欢迎的,但poker模块的周期性导入是彻头彻尾的谴责,因为这个问题创建了两个相同的(ish)命名空间以及可能产生的奇怪错误。

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

1)__main__

因为您正在执行from poker_test import *,而不是将import *中创建的所有变量放在其自己的命名空间中,而是将其抛入poker_test命名空间。

2)__main__

因为如果模块是正在执行的主脚本,您只从if __name__=='__main__':导入,那么从poker_test导入poker时,Python解释器将不会触及该行。所以你的代码在概念上并没有真正循环。 poker_testpoker导入__main__导入poker_test并停在那里。简单!

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

一些参考资料:

Official Python 3.4.2 docs on the import system

2008 comp.lang.python discussion on cyclical imports

答案 1 :(得分:2)

总是最难避免像你在这里创建的循环依赖。但是你运气好,因为from poker_test import *出现在poker.py的最后,即在后者定义了它所定义的所有内容之后,所以它可以通过循环依赖{导入一个良好的状态} {1}}。

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

  • 移动所有"实质性" poker_test.py检查之前poker.py的内容,例如if __name__
  • _poker.py中,只需执行poker.py
  • from _poker import *中,而不是poker_test.py,请使用import poker

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