我用the 'standard' minimal structure写了一个包.它看起来像这样:
my_package/
my_package/
__init__.py
setup.py
__init__.py
包含一个类,因此可以像预期的那样简单地导入和使用。
但是,该代码确实适合以命令行方式使用,例如
python my_package --arg1 "I like bananas."
起初,我只是有一个 if __name__ == '__main__'
检查 __init__
然后使用 argparse
。这有效,但它并不漂亮,因为这意味着您将像这样从命令行调用它:
python my_package/__init__.py --arg1 "I like bananas."
根据我的阅读,这是一个 __main__.py
文件的来源,该文件将作为文件夹内的默认脚本执行(类似于 index.html
网站上的文件)。我的想法是然后简单地导入 __init__.py
,运行 argparse 并将参数提供给类构造函数。像这样:
import argparse
from __init__ import MyClass
parser = argparse.ArgumentParser()
parser.add_argument("--arg1", help="Some dummy value")
args = parser.parse_args()
my_class = MyClass(**vars(args))
my_class.do_stuff()
类似的包应该是这样构建的,还是有更好的方法?
上面的工作但是 PyCharm 告诉我 __main__.py
__init__
是一个未解析的引用。与该导入行上的 MyClass
相同。当我使用 .__init__
代替(带点)时,警告消失但代码不再工作,给我一个 ImportError: attempted relative import with no known parent package
.
最佳答案
我想向您推荐一个不同的结构:
my_package/
my_package/
__init__.py
cli_scripts.py
setup.py
假设您的 __init__.py
看起来像这样(作为旁注,我建议将其中定义的类移动到一个单独的文件中,然后简单地将该文件导入 __init__
):
class Test(object):
def __init__(self, a)
self.a = a
def __call__(self):
print(self.a)
现在包内有一个额外的文件,它利用了您在包中实现的内容,我们称它为 cli_scripts.py
:
import argparse
from my_package import Test
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("a", type=int, help="Just an example argument")
return parser.parse_args()
def demonstration():
args = parse_args()
t = Test(a=args.a)
t()
我现在的建议是利用 console_scripts entry point在 setup.py
中,现在看起来像这样:
from setuptools import setup
setup(
name='testpy',
version='0.1',
description='Just an example',
author='RunOrVeith',
author_email='xyz@mailinator.com',
packages=["my_package"],
entry_points={
"console_scripts": ["mypkg=my_package.cli_scripts:demonstration"]},
install_requires=[],
)
现在,当您在顶级 my_package
文件夹中运行 pip install .
时,您的包将被安装。 entry_points
自动为您生成一个可执行文件,您现在可以使用您在 setup.py
中给它的名称调用它,在本例中为 mypkg
.这意味着您现在可以运行
mypkg 5
这将调用 demonstration()
。
这样:
- 你不需要处理任何
__main__
文件 - 你可以给你的脚本一个有意义的名字
- 你不需要关心你的脚本是否可执行,或者指定用
python
运行脚本 - 你可以在列表
entry_points
中拥有任意数量的这些
- 它迫使你编写你也可以从其他模块调用的函数,
而不是
__main__
我认为这很干净。
您可以在 this blog 中阅读有关 entry_points
的更多信息,它有更多的功能!
如果你想使用 __main__
中指定的代码而不是这种 cli_scripts
方法,你可以看看 this question .
关于python - 也可以作为命令行脚本运行的包结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53865866/