我正在使用 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
电话,但这看起来不太好。有什么建议吗?
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
函数需要一个可变对象。
__call__
方法。 (我是从 Java 环境中学习 Python 的,很长一段时间都怀念这个功能。)
def __call__(self, yt) -> None:
initialize_upload(yt, self)
你现在可以这样称呼它:
UploadOptions(title=custom_title, file=custom_file)(youtube)
这是因为像函数一样调用实例会隐式调用该实例的 call 方法。
自己创建参数
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使用率。