如何将基于 cli 的参数函数转换为采用 python 参数的函数

问题描述 投票:0回答:1

我正在使用 google-api-python-client 库中的示例函数,该函数接受命令行参数并使用

argparser
解析它们。这是基于的代码(转换为 python3)https://developers.google.com/youtube/v3/guides/uploading_a_video

if __name__ == '__main__':
    argparser.add_argument("--file", required=True,
                           help="Video file to upload")
# ...bunch of possible arguments
    args = argparser.parse_args()
    youtube = get_authenticated_service(args)
    try:
        initialize_upload(youtube, args)
然后,top 函数将参数作为

run_flow

 参数传递给 oauth 库中的 
flags
 函数。该函数需要命令行参数:

It presumes it is run from a command-line application and supports the following flags:
有没有一种方法可以干净地参数化这个函数,以便我可以轻松地从另一个 python 函数调用它?我已经搞乱了创建一个包装函数,将这些参数设置为默认值。

def uploadVideo(file, title, description, category): # this feels hacky (yah think?) argparser.add_argument("--file", required=True, help="Video file to upload", default=file) argparser.add_argument("--title", help="Video title", default=title)
我也开始写一个 

subprocess.run

 电话,但这看起来不太好。

有什么建议吗?

python parameters arguments command-line-interface
1个回答
0
投票
免责声明

首先:我要说的是,我正在黑暗的一面工作,所以我没有工具来安装上传程序包。因此,如果解决方案不起作用,请告诉我。

parse_args 如何工作

阅读了

parse_args 文档和一些源代码之后。我认为该方法看起来像这样:

from typing import Any # helper class to have a namespace that can be dynamically manipulated class Namespace: pass def parse_args(args: list[str] | None = None, namespace: Any | None = None): if args is None: args = sys.argv[1:] if namespace is None: namespace = Namespace() # ommitting the args parsing logic # iterating over the parsed results and adding them as instance attributes # to the above created namespace instance. These attributes can be accessed # in the normal way (object.attribute) and are only visible in that # specific instance. for parameter, value in parsed_args: setattr(namespace, parameter, value)
这意味着我们有两种方法来解决所要求的问题。

创建一个数据类(或提供一个鸭子类型的替代方案)

我认为这种方法更干净、更容易理解。

from dataclasses import dataclass @dataclass(frozen=True) class UploadOptions: file: str title: str # This should not be necessary, but argparse.Namespace implements it, so it is better ducktyping. def __contains__(self, key) -> bool: return hasattr(self, key) initialize_upload(youtube, UploadOptions(title=custom_title, file=custom_file))


数据类装饰器是一个很酷的工具,可以减少样板代码。它为我们实现了

__init__

__eq__
__repr__
 方法,通过 
frozen=True
,我们还获得了不变性和 
__hash__
 函数。

如果您收到类似这样的错误消息

dataclasses.FrozenInstanceError: cannot assign to field 'bar'

尝试删除冻结(或将其显式设置为False),则
initiliaze_upload
函数需要一个可变对象。


也许您可以给 UploadOptions 类提供一些语法糖,实现

__call__

 方法。
(我是从 Java 环境中学习 Python 的,很长一段时间都怀念这个功能。)

def __call__(self, yt) -> None: initialize_upload(yt, self)
你现在可以这样称呼它:

UploadOptions(title=custom_title, file=custom_file)(youtube)
这是因为像函数一样调用实例会隐式调用该实例的 

call 方法。

自己创建参数

但这只是你的hacky解决方案的另一种方法,对我来说,感觉不那么hacky,但也很hacky。我更喜欢第一个解决方案,只有当另一个解决方案失败时才选择这个解决方案。

argparser = argparse.ArgumentParser() argparser.add_argument("--file", required=True, help="Video file to upload") argparser.add_argument("--title", help="Video title") def uploadVideo(file: str | None = None, title: str | None= None): args: list[str] = [] if file is not None: args.extend(['--file', file]) if title is not None: args.extend(['--title', title]) parsed = argparser.parse_args(args=args) initialize_upload(youtube, parsed)
当然,你也可以在函数中创建argparser,但这样你只创建一个ArgumentParser实例并多次使用它,这样可以降低CPU使用率。

© www.soinside.com 2019 - 2024. All rights reserved.