分发关键字参数的最佳方式是什么?

6

什么是在调用函数时分配关键字参数的批准编程模式?

考虑这个编写的(并且有缺陷的)例子:

def create_box(**kwargs):
    box = Box()
    set_size(box, **kwargs)
    set_appearance(box, **kwargs)

def set_size(box, width=1, height=1, length=1):
    ...

def set_appearance(box, material='cardboard', color='brown'):
    ...

显然,set_size() 方法不接受 materialcolor 关键字参数,就像 set_appearance() 拒绝接收 widthheightlength 参数一样。
有一个合理的观点认为,create_box() 应该将所有关键字和默认值都明确化,但显而易见的实现方法相当笨重:
def create_box(width=1, height=1, length=1, material='cardboard', color='brown'):
    box = Box()
    set_size(box, width=width, height=height, length=length)
    set_appearance(box, material=material, color=color)

有没有更符合Python风格的方法来处理这个问题?


在我看来,试图将一长串参数隐藏在kwargs中可能会导致运行时错误,这种错误通常比明确列出参数更难处理。 - DaveBensonPhillips
3个回答

5
你可以将**kwargs作为最后一个参数添加到那些本来会变得烦躁的函数中。
def create_box(**kwargs):
    box = Box()
    set_size(box, **kwargs)
    set_appearance(box, **kwargs)

def set_size(box, width=1, height=1, length=1, **kwargs):
    ...

def set_appearance(box, material='cardboard', color='brown', **kwargs):
    ...

3

假设您不能更改set_sizeset_appearance,则可以根据预期的关键字参数过滤kwargs,但我不确定这是否是最符合Python风格的方法...

import inspect

def create_box(**kwargs):
    box = None
    set_size_args = inspect.getargspec(set_size).args
    set_size(box, {k:v for k,v in kwargs.items() if k in set_size_args})
    set_appearance_args = inspect.getargspec(set_appearance).args
    set_appearance(box, {k:v for k,v in kwargs.items() if k in set_appearance_args})


def set_size(box, width=1, height=1, length=1):
    pass

def set_appearance(box, material='cardboard', color='brown'):
    pass

create_box(width=1, height=1, length=1, material='', color='')

(适用于Python 3)请使用inspect.signature()

1

个人而言,我会传递一个包含所需参数的对象。这样,您只需一直传递一个参数。

示例:

class BoxDefinition:
    def __init__(self, width=1, height=1, length=1, material='cardboard', color='brown'):
        self.width = width 
        self.height = height
        # and so on for the rest of the params ...

在每个方法内部,您可以从此对象中读取:

def create_box(box_definition):
    box = Box()
    set_size(box, box_definition)
    set_appearance(box, box_definition)

def set_size(box, box_definition):
    width = box_definition.width

def set_appearance(box, box_definition):
    color = box_definition.color

然后您可以像这样调用它:
definition = BoxDefinition(width=2, height=3, length=4)
create_box(definition)

事实上,您甚至可以将BoxDefinition作为Box类的属性,这样您只需要传递Box即可。

如果您的函数共享相同的 kwarg 但具有不同的默认值,则可能会变得难以处理。 - r.ook
公正的观点,我认为在OP的情况下,这种情况不会发生,因为kwargs集在函数之间是唯一的。 - LeKhan9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接