是否可以将相同的可选参数传递给多个函数?

时间:2017-10-13 22:51:31

标签: python python-3.x function optional-arguments

我想问一下,当将相同的参数传递给函数的可选参数时,是否有办法防止不必要的代码重复。

希望以下示例能够很好地了解我要做的事情:

def f(arg1):
    def g(optional_1=0, optional_2=0, optional_3=0):
        return arg1+optional_1+optional_2+optional_3
    return g

b, c = 2, 3
f1 = f(1)
f2 = f(2)
calc_f1 = f1(optional_2=b, optional_3=c)
calc_f2 = f2(optional_2=b, optional_3=c)

正如您所看到的,f1和f2仅在传递给f的arg1中有所不同,之后我使用相同的可变参数的相同变量调用它们。 当代码很短时,它很好,但是当我有超过10个可选参数时,它变得不必要地冗长冗余。 是否可以做类似

的事情
optional_variable_pair = #some way to combine them
calc_f1 = f1(optional_variable_pair)
calc_f2 = f2(optional_variable_pair)

所以我得到了一个更简洁易读的代码?

3 个答案:

答案 0 :(得分:1)

任何带有多个可选参数的函数都有点臭,因为:

  1. 你得到了很多参数组合,需要大量的测试。
  2. 因为所有选项,函数必须有很多条件和路径,这会增加其圈复杂度。
  3. 您可以应用重构将整个参数列表提取到Object中,并使该函数在该对象上起作用。如果你能找到一个描述你的参数列表的统一名称并且适合你在函数周围使用的任何比喻,那么这种方法非常有效。你甚至可以反转调用,使函数成为Object的一个方法,所以你得到了一些封装。

答案 1 :(得分:0)

您使用键值对作为函数结果,为此您可以使用* args和** kwargs:

optional_variable_pair = {
  "optional_1": 1,
  "optional_2": 2,
  "optional_3": 3,
}
calc_f1 = f1(**optional_variable_pair)
calc_f2 = f2(**optional_variable_pair)

答案 2 :(得分:0)

要回答你提出的问题,答案是肯定的。您可以使用关键字参数解包来完成您想要的任何操作。

def f(arg1):
    def g(optional_1=0, optional_2=0, optional_3=0):
        return arg1+optional_1+optional_2+optional_3
    return g

optional_variable_pair = {
    'optional_2': 2,
    'optional_3': 3
}

f1 = f(1)
f2 = f(2)
calc_f1 = f1(**optional_variable_pair)
calc_f2 = f2(**optional_variable_pair)

如果我正确地阅读你的意图,你的问题的本质是想要将新的第一个参数与相同的连续参数传递给函数。根据您的使用情况,可能不需要包装函数g

def f(arg1, *, optional_1=0, optional_2=0, optional_3=0):
    return optional_1 + optional_2+optional_3

optional_variable_pair = {
    'optional_2': 2,
    'optional_3': 3
}

calc_f1 = f(1, **optional_variable_pair)
calc_f2 = f(2, **optional_variable_pair)

显然,如果第一个参数继续递增1,则for循环是有序的。显然,如果您从未使用optional_1参数,则不需要包含它。但是,此外,如果您发现自己使用带编号的参数,那么您很可能真的应该使用元组解包而不是关键字解包:

def f(*args):
    return sum(args)

optional_variable_pair = (2, 3)

for i in range(1, 3):
    calc = f(i, *optional_variable_pair)
    # ...do something with calc...

您可能也有兴趣研究functools.partial,它可以取代您的包装函数g,并允许这样做:

import functools

def f(*args):
    return sum(args)

f1 = functools.partial(f, 1)
f2 = functools.partial(f, 2)

calc_f1 = f1(2, 3) # = 1 + 2 + 3 = 6
calc_f2 = f2(2, 3) # = 2 + 2 + 3 = 7