背景:
我有一个像这样的目录结构:
Package/
setup.py
src/
__init__.py
__main__.py
code.py
我希望能够以多种不同的方式运行代码。
pip install Package
然后python
然后from Package import *
python -m Package
应该做的事情__main__.py
python __main__.py
这也应该在__main__.py
但是这次,我们假设你下载的是源代码而不是pip installing
现在我已经开始使用前两个了,但是设置很乱:
安装程序.py:
setup(
name='Package',
packages=['Package'],
package_dir={'Package': 'src'},
...
entry_points={ 'console_scripts': ['Package = src.__main__:main' ] }
init.py:
from Package.code import .......
main.py:
from . import .......
在这两种情况下,对我来说更有意义的是写
from code import ........
但这给了我导入错误。
问题:
我拥有它的方式真的是唯一的方式吗?
最重要的是,我如何支持第三个用例?现在, python __main__.py
抛出
File "__main__.py", line 10, in <module>
from . import code
ImportError: cannot import name 'class defined in code.py'
笔记:
我读过了
- https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/
- http://setuptools.readthedocs.io/en/latest/setuptools.html
- 这里有很多问题看起来像这个,但没有回答我上面的问题。
原文由 Alex Lenail 发布,翻译遵循 CC BY-SA 4.0 许可协议
您几乎拥有所需的一切(甚至更多)!我会使用以下设置:
代码.py :
init.py:
在这里进行相对导入,因为
__init__.py
将在导入整个包时使用。请注意,我们通过使用.
语法将导入显式标记为相对导入,因为这是 Python 3 所必需的(在 Python 2 中,如果您这样做了from __future__ import absolute_import
)。main.py:
这是包的主要脚本,因此我们使用绝对
import
语句。通过这样做,我们假设包已经安装(或者至少已经放在路径上);这就是处理包裹的方式!您可能认为这与您的第三个用例冲突,但实际上在处理包时没有理由 不pip install
。这真的没什么大不了的(尤其是在使用virtualenv
时)!如果您关心的是修改源文件并通过运行
__main__.py
文件轻松观察更改,那么您只需使用-e
(“可编辑”)开关安装包:pip install -e .
(假设你在目录中Package
)。但是,对于您当前的目录结构,这将不起作用,因为-e
开关会将egg-link
放置到包含setup.py
文件的目录;该目录不包含名为Package
的包,而是src
包(我对此有 疑问)。相反,如果您按照约定在包本身之后命名包源的根目录(即
Package
例如),那么安装-e
不是问题:Python 确实在相应目录下找到 了需要的包Package
:这也让您可以省略
package_dir={'Package': 'src'}
中setup.py
的额外定义。关于
setup.py
的注释:对于您指定的三个用例,无需定义入口点。也就是说,您可以跳过该行entry_points={ 'console_scripts': ['Package = src.__main__:main' ] }
。通过运送__main__.py
模块python -m Package
将轻松执行此模块中的代码。您还可以添加一个额外的 if 子句:另一方面,入口点让您可以直接从 CLI 执行
__main__.main
中的代码;正在运行的$ Package
将执行相应的代码。回顾
最重要的是,在处理包时,我总是使用
pip install
。为什么不呢,特别是如果您已经创建了一个setup.py
文件?如果要“实时”应用对包的更改,则可以使用-e
开关安装(这可能需要重命名src
文件夹,见上文)。因此,您的第三个用例将读作“下载源代码和pip install (-e) Package
(在 virtualenv 中);然后您可以运行python __main__.py
”。编辑
运行
__main__.py
没有pip install
如果你不想通过 pip 安装包但仍然能够运行
__main__.py
脚本,我仍然会使用上面的设置。然后我们需要确保from Package import ...
语句仍然成功,这可以通过扩展导入路径来实现(请注意,这需要重命名src
目录到包裹的名字!)。修改
PYTHONPATH
对于 Linux bash,您可以按如下方式设置 Pythonpath:
或者,如果您与
__main__.py
在同一目录中:当然不同的操作系统有不同的方法。
扩展路径
__main__.py
您(或者您的同事)可以将以下行添加到脚本的顶部(在
from Package import ...
语句之前):扩展路径
sitecustomize.py
您可以将名为
sitecustomize.py
的模块放置在 Python 安装的lib/python3.5/site-packages/
目录中,其中包含以下行:创建一个单独的顶级
main.py
脚本所以你会有以下布局:
其中
main.py
包含现在
__main__.py
被视为src
包的一部分,相关导入将起作用。而不是运行python src/__main__.py
你现在运行python main.py
。