我应该在 __main__.py 中使用啥形式的导入,然后我应该如何运行项目?
Posted
技术标签:
【中文标题】我应该在 __main__.py 中使用啥形式的导入,然后我应该如何运行项目?【英文标题】:What form of imports should I use in __main__.py and then how should I run the project?我应该在 __main__.py 中使用什么形式的导入,然后我应该如何运行项目? 【发布时间】:2020-11-28 01:26:23 【问题描述】:假设我有以下简单的项目结构。
project/
package/
__init__.py
__main__.py
module.py
requirements.txt
README.md
在对 Google 进行了一些研究之后,我试图让它反映一个非常简单的控制台应用程序的一般最佳实践(但不像简单地拥有一个脚本那么简单)。假设__init__.py
只包含print("Hello from __init__.py")
,而module.py
包含类似的语句。
我应该如何在__main__.py
内部进行导入,然后我应该如何运行我的项目?
首先让我们说__main__.py
看起来很简单:
import module
print("Hello from __main__.py")
如果我使用简单的命令 python package
运行我的项目,我会得到以下输出:
Hello from module.py
Hello from __main__.py
可以看出,__init__.py
没有运行。我认为这是因为我将项目的包作为脚本运行。如果我改为使用命令python -m package
将其作为模块运行,我会得到以下输出:
Hello from __init__.py
Traceback (most recent call last):
File "C:\Users\MY_USER\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\MY_USER\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "C:\Users\MY_USER\PATH\TO\PROJECT\project\package\__main__.py", line 1, in <module>
import module
ModuleNotFoundError: No module named 'module'
如果我将__main__.py
中的第一行更改为import package.module
并再次运行python -m package
,我会得到以下输出:
Hello from __init__.py
Hello from module.py
Hello from __main__.py
太棒了!将我的项目包作为模块运行时,现在似乎一切正常。现在,如果我再次尝试 python package
并将其作为脚本运行会怎样?
Traceback (most recent call last):
File "C:\Users\MY_USER\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\MY_USER\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "package\__main__.py", line 1, in <module>
import package.module
ModuleNotFoundError: No module named 'package'
好的。因此,如果我错了,请纠正我,但似乎我有两个选择。我可以在我的包中编写导入以将其作为脚本运行或作为模块运行,但不能同时运行。哪个更好,如果确实更可取,为什么?你什么时候使用命令python package
vs python -m package
,为什么?在我可能不理解的简单项目中编写导入是否有一些一般规则?我是否缺少其他基本内容?
总结:在这种情况下,最佳做法是什么,为什么它是最佳做法,以及您何时将项目设置为替代方法(python package
与 python -m package
)?
【问题讨论】:
【参考方案1】:分发可执行 python 代码的最常见方法是将其打包到可安装的.wheel
文件中。如果它只是一个文件,您也可以分发它。但是,一旦您获得两个文件,就会遇到您遇到的确切导入问题,此时您需要一些元数据来为导入提供明确定义且可见的顶层(例如,在您的情况下为 package.module
) 、脚本代码的入口点、第三方依赖...所有这些都是通过“使代码可安装”来实现的。
如果您喜欢技术文档,您可以阅读 Python 打包机构 (PyPA) 提供的 this 和 this 教程,了解其具体含义。
不过,为了让您开始您的项目,您缺少的是一个 setup.py
文件,该文件将包含安装说明和一个脚本入口点,以提供一种从包中运行可执行代码的方法:
from setuptools import setup
with open("requirements.txt") as f:
requirements = [line.strip() for line in f.readlines()]
setup(
# obligatory, just the name of the package. you called it "package" in your
# example so that's the name here
name="package",
# obligatory, when it's done you can give it a 1.0
version="0.1",
# point the installer to the module (read, folder) that contains your code,
# by convention usually the same as the package name
packages=["package"],
# if there are dependencies, specify them here. actually you can delete the
# requirements.txt and just paste the content here, but this here will also work
install_requires=requirements,
# point the installer to the function that will run your executable code.
# the key name has got to be 'console_script', the value content is up
# to you, with its interpretation being:
# 'package_command' -> the name that you can call your code by
# 'package.__main__' -> the path to the file that you want to call
# 'test' -> the actual function that contains the code
entry_points='console_scripts': ['package_command=package.__main__:test']
)
将此文件添加为project/setup.py
后,您需要牢记以下几点:
print('hello world)'
)放入您的__main__.py
文件中名为test
的函数中[1]
运行pip install -e .
在本地安装你的包[2]
通过在命令行上运行 package_command
来执行脚本代码 - python package
和 python -m package
都不是运行可安装 python 脚本的最佳实践
[1] 将一个简单的函数绑定到一个脚本入口点是最基本的。您可能不想重新发明诸如帮助文本、参数解析/验证之类的东西……所以如果您真的想编写一个 cli 应用程序,您可能需要查看类似 click
的东西来处理对你来说乏味的东西。
[2] 这将执行开发安装,这在开发过程中很方便,因为这意味着您可以在处理它时测试行为。如果你想分发你的代码,你会运行pip wheel .
(可能需要在之前运行pip install wheel
)。这将创建一个 wheel 文件,您可以将其提供给您的客户,以便他们可以使用 pip install package-0.1-py3-none-any.whl
手动安装它,之后package_command
也将在他们的系统上可用。
【讨论】:
以上是关于我应该在 __main__.py 中使用啥形式的导入,然后我应该如何运行项目?的主要内容,如果未能解决你的问题,请参考以下文章
如何简单地理解Python中的if __name__ == '__main__'