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

Python 是否可以将相同的可选参数传递给多个函数?,python,python-3.x,function,optional-arguments,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(optiona

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

希望下面的示例能够很好地说明我正在尝试做什么:

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)

因此,我得到了一个更简洁易读的代码?

您使用键值对作为函数参数,为此,您可以使用*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)

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

  • 你会得到太多的参数组合,这需要大量的测试
  • 由于所有的选项,函数必须有大量的条件和路由,这增加了它的圈复杂度

  • 您可以应用重构将整个参数列表提取到一个对象中,并让函数在该对象上工作。如果你能找到一个统一的名称来描述你的参数列表,并且适合你在函数中使用的任何隐喻,那么这个方法非常有效。您甚至可以反转调用,使函数成为对象的一种方法,从而得到一些封装。

    要回答您提出的问题,答案是肯定的。使用关键字参数解包,您几乎可以完全按照自己的意愿进行操作

    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
    循环。显然,如果您从未使用
    可选_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
    

    我不确定我是否完全理解您的问题,但您是否尝试过使用splat运算符(
    *
    )?听起来它可能会对您有所帮助。根据这些函数是什么以及您使用返回值的目的,最好在循环或列表中调用这些函数,而不是尝试缩短调用语法。谢谢您的回复。我知道*可以用于解包元组或列表,但我需要将它们与各自的可选参数相关联,我不知道*是否可以实现这一点。@KevinLin Iirc,您可以解包一个与可选参数名称键相同的字典。您对
    plt.plot()
    有何看法?它有很多参数,但我认为它很好。在将一个对象传递给一个函数方面,dict对我来说就是这样的。简单地看了一下它的文档,我觉得它很臭。我还认为我对它的领域了解不够,无法做出明智的判断。气味的意义不在于它们告诉你有什么不对劲,它们告诉你很可能有什么不对劲。在plt.plot的领域中,也许没有更好的方法来表示功能。