直接从 python @click 创建结构化数据?
create structured data directly from python @click?
正如所讨论的 从几个脚本轻松。
然而,随着参数数量的增加
- main 函数参数列表变得拥挤和 voids pylint
too-many-arguments
- 处理这么多参数的代码在 WET 编程中结束
- 如果一个人有多个脚本使用这些参数,即使是相似代码的多个地方也必须维护
所以,有没有办法直接在装饰器中创建一个class对象来对参数进行分组?
所以,从这样的装饰函数:
def common_options(mydefault=True):
def inner_func(function):
function = click.option('--unique-flag-1', is_flag=True)(function)
function = click.option('--bar', is_flag=True)(function)
function = click.option('--foo', is_flag=True, default=mydefault)(function)
return function
return inner_func
像这样直接发出一个class:
class CommonOptions:
def __init__(unique_flag_1, bar, foo):
self.unique_flag_1 = ....
可以直接发射到
@click.command
@common_options()
def main(common_options: CommonOptions):
...
您可以在 click
命令中使用 **kwargs
,因此您可以这样写:
import click
from dataclasses import dataclass
@dataclass
class CommonOptions:
unique_flag_1: bool
bar: bool
foo: bool
def common_options(mydefault=True):
def inner_func(function):
function = click.option("--unique-flag-1", is_flag=True)(function)
function = click.option("--bar", is_flag=True)(function)
function = click.option("--foo", is_flag=True, default=mydefault)(function)
return function
return inner_func
@click.command()
@common_options()
def main(**kwargs):
options = CommonOptions(**kwargs)
print(options)
if __name__ == "__main__":
main()
W/r/t 你的评论,如果我们借用 的想法,我们可以这样写,我们可以有多个选项组,但对于每个组,我们只传递所有 **kwargs
让收件人整理一下:
import click
from dataclasses import dataclass
class OptionGroup:
@classmethod
def from_dict(cls, **options):
return cls(
**{k: v for k, v in options.items() if k in cls.__dataclass_fields__}
)
@dataclass
class OptionGroup1(OptionGroup):
unique_flag_1: bool
bar: bool
foo: bool
@dataclass
class OptionGroup2(OptionGroup):
count: int
size: int
def option_group_1(mydefault=True):
def _(function):
function = click.option("--unique-flag-1", is_flag=True)(function)
function = click.option("--bar", is_flag=True)(function)
function = click.option("--foo", is_flag=True, default=mydefault)(function)
return function
return _
def option_group_2():
def _(function):
function = click.option("--count", type=int)(function)
function = click.option("--size", type=int)(function)
return function
return _
@click.command()
@option_group_2()
@option_group_1()
def main(**kwargs):
o1 = OptionGroup1.from_dict(**kwargs)
o2 = OptionGroup2.from_dict(**kwargs)
print("group1:", o1)
print("group2:", o2)
if __name__ == "__main__":
main()
一些示例输出:
$ python example.py
group1: OptionGroup1(unique_flag_1=False, bar=False, foo=True)
group2: OptionGroup2(count=None, size=None)
$ python example.py --count=3 --bar
group1: OptionGroup1(unique_flag_1=False, bar=True, foo=True)
group2: OptionGroup2(count=3, size=None)
正如所讨论的
- main 函数参数列表变得拥挤和 voids pylint
too-many-arguments
- 处理这么多参数的代码在 WET 编程中结束
- 如果一个人有多个脚本使用这些参数,即使是相似代码的多个地方也必须维护
所以,有没有办法直接在装饰器中创建一个class对象来对参数进行分组?
所以,从这样的装饰函数:
def common_options(mydefault=True):
def inner_func(function):
function = click.option('--unique-flag-1', is_flag=True)(function)
function = click.option('--bar', is_flag=True)(function)
function = click.option('--foo', is_flag=True, default=mydefault)(function)
return function
return inner_func
像这样直接发出一个class:
class CommonOptions:
def __init__(unique_flag_1, bar, foo):
self.unique_flag_1 = ....
可以直接发射到
@click.command
@common_options()
def main(common_options: CommonOptions):
...
您可以在 click
命令中使用 **kwargs
,因此您可以这样写:
import click
from dataclasses import dataclass
@dataclass
class CommonOptions:
unique_flag_1: bool
bar: bool
foo: bool
def common_options(mydefault=True):
def inner_func(function):
function = click.option("--unique-flag-1", is_flag=True)(function)
function = click.option("--bar", is_flag=True)(function)
function = click.option("--foo", is_flag=True, default=mydefault)(function)
return function
return inner_func
@click.command()
@common_options()
def main(**kwargs):
options = CommonOptions(**kwargs)
print(options)
if __name__ == "__main__":
main()
W/r/t 你的评论,如果我们借用 **kwargs
让收件人整理一下:
import click
from dataclasses import dataclass
class OptionGroup:
@classmethod
def from_dict(cls, **options):
return cls(
**{k: v for k, v in options.items() if k in cls.__dataclass_fields__}
)
@dataclass
class OptionGroup1(OptionGroup):
unique_flag_1: bool
bar: bool
foo: bool
@dataclass
class OptionGroup2(OptionGroup):
count: int
size: int
def option_group_1(mydefault=True):
def _(function):
function = click.option("--unique-flag-1", is_flag=True)(function)
function = click.option("--bar", is_flag=True)(function)
function = click.option("--foo", is_flag=True, default=mydefault)(function)
return function
return _
def option_group_2():
def _(function):
function = click.option("--count", type=int)(function)
function = click.option("--size", type=int)(function)
return function
return _
@click.command()
@option_group_2()
@option_group_1()
def main(**kwargs):
o1 = OptionGroup1.from_dict(**kwargs)
o2 = OptionGroup2.from_dict(**kwargs)
print("group1:", o1)
print("group2:", o2)
if __name__ == "__main__":
main()
一些示例输出:
$ python example.py
group1: OptionGroup1(unique_flag_1=False, bar=False, foo=True)
group2: OptionGroup2(count=None, size=None)
$ python example.py --count=3 --bar
group1: OptionGroup1(unique_flag_1=False, bar=True, foo=True)
group2: OptionGroup2(count=3, size=None)