包的结构也可以是 运行 作为命令行脚本
Structure of package that can also be run as command line script
我用the 'standard' minimal structure写了一个包。它看起来像这样:
my_package/
my_package/
__init__.py
setup.py
__init__.py
包含一个 class,因此可以像预期的那样简单地导入和使用。
但是,该代码确实适合以命令行方式使用,例如
python my_package --arg1 "I like bananas."
起初,我只是在 __init__
中进行了 if __name__ == '__main__'
检查,然后使用 argparse
。这个 有效 但它并不漂亮,因为这意味着你会像这样从命令行调用它:
python my_package/__init__.py --arg1 "I like bananas."
根据我的阅读,这是 __main__.py
文件的来源,该文件将作为文件夹内的默认脚本执行(类似于网站上的 index.html
文件)。我的想法是然后简单地导入 __init__.py
、运行 argparse 并将参数提供给 class 构造函数。像这样:
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()
我现在的建议是利用 setup.py
中的 console_scripts entry point,现在看起来像这样:
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=[],
)
现在,当您 运行 pip install .
在顶级 my_package
文件夹中时,您的软件包将被安装。 entry_points
自动为您生成一个可执行文件,您现在可以使用您在 setup.py
中给它的名称调用它,在本例中为 mypkg
。这意味着您现在可以 运行
mypkg 5
这将调用 demonstration()
。
这样:
- 您不需要处理任何
__main__
个文件
- 你可以给你的脚本一个有意义的名字
- 你不需要关心你的脚本是否可执行,或者用
python
指定运行脚本
- 您可以在列表中添加任意数量的这些内容
entry_points
- 它迫使你编写你也可以从其他模块调用的函数,
而不是
__main__
我觉得这很干净。
您可以在 this blog 中阅读更多关于 entry_points
的信息,它有更多的功能!
如果您想使用 __main__
中指定的代码而不是这种 cli_scripts
方法,您可以查看 .
我用the 'standard' minimal structure写了一个包。它看起来像这样:
my_package/
my_package/
__init__.py
setup.py
__init__.py
包含一个 class,因此可以像预期的那样简单地导入和使用。
但是,该代码确实适合以命令行方式使用,例如
python my_package --arg1 "I like bananas."
起初,我只是在 __init__
中进行了 if __name__ == '__main__'
检查,然后使用 argparse
。这个 有效 但它并不漂亮,因为这意味着你会像这样从命令行调用它:
python my_package/__init__.py --arg1 "I like bananas."
根据我的阅读,这是 __main__.py
文件的来源,该文件将作为文件夹内的默认脚本执行(类似于网站上的 index.html
文件)。我的想法是然后简单地导入 __init__.py
、运行 argparse 并将参数提供给 class 构造函数。像这样:
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()
我现在的建议是利用 setup.py
中的 console_scripts entry point,现在看起来像这样:
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=[],
)
现在,当您 运行 pip install .
在顶级 my_package
文件夹中时,您的软件包将被安装。 entry_points
自动为您生成一个可执行文件,您现在可以使用您在 setup.py
中给它的名称调用它,在本例中为 mypkg
。这意味着您现在可以 运行
mypkg 5
这将调用 demonstration()
。
这样:
- 您不需要处理任何
__main__
个文件 - 你可以给你的脚本一个有意义的名字
- 你不需要关心你的脚本是否可执行,或者用
python
指定运行脚本
- 您可以在列表中添加任意数量的这些内容
entry_points
- 它迫使你编写你也可以从其他模块调用的函数,
而不是
__main__
我觉得这很干净。
您可以在 this blog 中阅读更多关于 entry_points
的信息,它有更多的功能!
如果您想使用 __main__
中指定的代码而不是这种 cli_scripts
方法,您可以查看