我应该在__main__.py中使用什么形式的导入,然后我应该如何运行项目



假设我有以下简单的项目结构。

project/
package/
__init__.py
__main__.py
module.py
requirements.txt
README.md

在对谷歌进行了一些研究后,我试图让它反映出一个非常简单的控制台应用程序的一般最佳实践(但不是简单地拥有一个脚本那么简单(。假设__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:UsersMY_USERAppDataLocalProgramsPythonPython38librunpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:UsersMY_USERAppDataLocalProgramsPythonPython38librunpy.py", line 87, in _run_code
exec(code, run_globals)
File "C:UsersMY_USERPATHTOPROJECTprojectpackage__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:UsersMY_USERAppDataLocalProgramsPythonPython38librunpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:UsersMY_USERAppDataLocalProgramsPythonPython38librunpy.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 packagepython -m package,为什么?在一个我可能不理解的简单项目中编写导入是否有一些通用规则?我是不是错过了其他一些基本的东西?

总之:在这种情况下,什么是最佳实践,为什么是最佳实践?您何时将项目设置为替代方法(python packagepython -m package(?

分发可执行python代码的最常见方法是将其打包到可安装的.wheel文件中。如果它只是一个文件,您也可以直接分发它。但是,一旦您获得两个文件,就会遇到您遇到的确切导入问题,在这一点上,您需要一些元数据来为导入(例如,在您的情况下是package.module(、脚本代码的入口点、第三方依赖关系。。。所有这些都是通过";使得代码是可安装的";。

如果你喜欢技术文档,你可以通过阅读python打包机构(PyPA(的本教程和本教程来了解这到底意味着什么。


不过,要开始您的项目,您缺少的是一个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(。这将创建一个轮子文件,您可以将其提供给客户端,以便他们可以使用pip install package-0.1-py3-none-any.whl手动安装,之后package_command也将在其系统上可用

相关内容

  • 没有找到相关文章

最新更新