带有doctest的Python项目中的导入
我有一个Python项目,目录结构如下:
/(some files) /model/(python files) /tools/(more python files) ...
在这个项目里,我有几个子目录,每个目录里都有Python文件,并且这些目录之间有一些依赖关系,比如工具会被模型使用等等。现在我的问题是,我想为models和tools都写一些文档测试,并且希望能通过命令行像这样运行测试:./model/car.py。我能做到这一点,但需要写很多繁琐的代码。我想知道有没有正确的方法,或者说有没有什么好的解决方案?
问题:我应该怎么写我的导入语句?
谢谢!这里有个例子...
tools/tool.py的内容:
#!/usr/bin/env python
"""
>>> is_four(21)
False
>>> is_four(4)
True
"""
def is_four(val):
return val == 4
if __name__ == '__main__':
import doctest
doctest.testmod()
... 还有model/car.py:
#!/usr/bin/env python
"""
>>> car = Car()
>>> car.ok()
True
"""
from tools.tool import *
class Car(object):
def __init__(self):
self.tire_count = 4
def ok(self):
return is_four(self.tire_count)
if __name__ == '__main__':
import doctest
doctest.testmod()
我在car.py的开头加了以下几行代码,这样可以运行,但看起来不太好。 :(
if __name__ == '__main__':
import sys
import os
sys.path.append(os.path.abspath(os.path.dirname('..')))
3 个回答
不要以这种方式去修改 sys.path
。相反,你可以在运行 python
的时候使用 $PYTHONPATH
来指定基础目录,或者直接在那个目录下使用 python -m model.car
来运行。
使用包。你需要在你的工作目录和所有子文件夹里添加一个 __init__.py
文件,这样当你导入模块时,如果当前目录找不到这个模块,它会去上级目录里找。
可以参考这个链接了解更多信息:http://www.network-theory.co.uk/docs/pytut/Packages.html
另外,这个问题和以下内容是重复的:
你想做的是相对导入。在Python中,这个功能是可以正常工作的,但它是基于模块的层级,而不是文件系统的层级。我知道,这听起来有点复杂。
这意味着,如果你在一个子目录中运行脚本,它看不到上层目录,因为对于正在运行的脚本来说,模块的根目录就是当前目录:没有上层模块。
那么,相对导入有什么用呢?
其实,子目录中的模块可以导入上层目录中的模块,只要这些模块本身是从上层目录导入的。
在你的情况下,这意味着你必须从根目录“/”来运行你的脚本,这样它就成为模块的根目录,子模块就可以使用相对导入。
解决你问题的一个方法是去掉你的 if __name__ == "__main__"
这部分代码,然后创建一个 /tests.py 文件:
import doctest
from model import car
from tools import tool
doctest.testmod(car)
doctest.testmod(tool)
然后在这里运行所有的测试。
最终,你会想要自动化这个过程,一个简单的解决方案是使用 unittest,这样你可以创建测试套件,只需添加你想测试的模块名称:
import unittest
import doctest
modules = ("model.car",
"tools.tool")
suite = unittest.TestSuite()
for mod in modules:
suite.addTest(doctest.DocTestSuite(mod))
runner = unittest.TextTestRunner()
runner.run(suite)
另一个推荐的解决方案是使用像 nose 这样的工具,它可以为你自动化这个过程。
easy_install nose
nosetests --with-doctest # done :-)
顺便说一下,尽量避免使用 from x import *
。这在快速编写脚本时可以用,但当你的程序变得复杂时,你真的需要明确地指定你要导入的内容。可以用 import x
或者 from x import y
。