到目前为止,我已经处理过几个中型python应用程序,而且每次我似乎都在拼凑一个糟糕的进口系统,从切向Stack Overflow的答案和半懂的博客文章。它很丑陋,难以维护,最终非常不满意。有了这个问题,我试图把所有这些都放在我身后。
假设我将python应用程序拆分为以下文件:
app.py
constants.py
ui/window.py
web/connection.py
具有以下包含要求:
app.py
需要包含window.py
和connection.py
window.py
需要包含constants.py
和connection.py
connection.py
需要包含constants.py
app.py
是应用程序的起点,但window.py
和connection.py
也可从命令行调用以测试基本功能(理想情况下来自各自的文件夹中)。
__init__.py
文件的组合,精心设计的导入语句和古怪的python路径魔法将允许我实现这种结构?
非常感谢,
- 丹
答案 0 :(得分:2)
如果不是首先考虑“文件结构”然后尝试找出包,而是根据包设计事物,然后布置文件结构来实现这些包,那真的很有帮助。
但是如果你想知道如何破解已有的东西:如果你把它放在顶层(即sys.path
上的一个路径中),并创建文件名{{ 1}}和ui/__init__.py
,然后:
web/__init__.py
可以作为脚本运行。app.py
可以使用app.py
。-m app
可以使用app.py
导入。import app
无法直接投放。window.py
可以使用window.py
。-m ui.window
可以使用window.py
导入。import ui.window
无法直接投放。connection.py
可以使用connection.py
。-m web.connection
可以使用connection.py
导入。不需要古怪的道路魔法;您只需要最高级别(import web.connection
,app.py
,constants.py
和ui
)位于web
- 您运行时自动生成将该目录作为工作目录,或将所有内容直接安装到sys.path
中,或将其安装为鸡蛋等。
这就像你要达到你想要的那样接近。您确实希望将包目录作为当前工作目录运行,或者以site-packages
运行,所以不要尝试。如果您认为自己需要,那么可能想要的是将可运行代码分离到可以放在顶层或完全独立的脚本中。 (例如,查看sys.path
或pip
,它会将脚本安装到系统ipython
上的某个位置,除了导入某个模块并运行函数之外什么都不做。)
您可能想要考虑的另一件事是将所有这些放入一个包中,比如$PATH
。您可以通过添加顶级myapp
,然后从父目录运行,并将__init__.py
添加到所有myapp.
和{的开头来实现。 {1}}陈述。这意味着您不能再将import
作为脚本运行,因此您需要再次将脚本代码拆分为与完成所有工作的模块分开的文件。
答案 1 :(得分:1)
只需稍加修改即可使用该结构:将空__init__.py
个文件添加到ui/
和web/
目录。然后,在您完成import window
的位置,执行import ui.window
或from ui import window
。同样,将import connection
更改为import web.connection
或from web import connection
。
基本原理:Python与目录的工作效果不如 packages ,这些目录中包含__init__.py
。通过将ui
和web
更改为包,您不必使用任何特定的Python路径魔法来处理它们,并且您可以获得为模块和导入添加一些结构的好处。如果您在不同的目录中开始使用具有相同名称的模块(例如util.py
和ui
目录中的web
,那将变得尤为重要;不一定是最干净的设计,但是你得到了主意)。
如果你直接调用window.py或connection.py来测试它们,你需要将顶级目录添加到你的PYTHONPATH中才能继续工作 - 但是还有一个微妙的额外皱纹。从顶级目录运行时:
PYTHONPATH=$PWD python web/connection.py
您现在拥有模块路径上的顶级目录和web/
目录。这可能导致某些相对进口做出意想不到的事情。
另一种方法是使用顶级目录中的Python -m
选项:
python -m web.foo
我知道很多人喜欢将他们的测试直接放入这样的模块中,但我还要注意,还有其他方法来构建测试,特别是使用更新的unittest
库和{{1随着项目变大,这将使运行测试变得更容易一些。请参阅此处的骨架以获得一个合理的示例: