44

我有一个带有两个可选参数的函数:

def func(a=0, b=10):
    return a+b

在我的代码的其他地方,我正在做一些条件参数传递,例如:

if a and b:
   return func(a, b)
elif a:
   return func(a)
elif b:
   return func(b=b)
else:
   return func()

无论如何要简化这种模式中的代码?

编辑

假设我不允许在内部实现默认参数逻辑func

我可能有几个函数,比如func: func1func2并且func3都包含

a = a or 0
b = b or 10

陈述。

但我正在调用这一系列函数来消除重复。(使用装饰器)

4

9 回答 9

63

如果您不想更改任何内容,func那么明智的选择是将参数的字典传递给函数:

>>> def func(a=0,b=10):
...  return a+b
...
>>> args = {'a':15,'b':15}
>>> func(**args)
30
>>> args={'a':15}
>>> func(**args)
25
>>> args={'b':6}
>>> func(**args)
6
>>> args = {}
>>> func(**args)
10

要不就:

>>>func(**{'a':7})
17
于 2012-06-25T09:12:51.513 回答
3

根据现在已删除的对检查的目的是针对变量None而不是错误的问题的评论,进行更改func以使其处理以下参数None

def func(a=None, b=None):
   if a is None:
      a = 0
   if b is None:
      b = 10

然后func(a, b)每次都打电话。

于 2012-06-25T08:13:17.763 回答
3

您可以添加一个装饰器来消除None参数:

def skip_nones(fun):
    def _(*args, **kwargs):
        for a, v in zip(fun.__code__.co_varnames, args):
            if v is not None:
                kwargs[a] = v
        return fun(**kwargs)
    return _

@skip_nones
def func(a=10, b=20):
    print a, b

func(None, None) # 10 20
func(11, None)   # 11 20
func(None, 33)   # 10 33
于 2012-06-25T08:21:19.887 回答
1

为了解决您的具体问题,我会这样做:

args = {'a' : a, 'b' : b}
for varName, varVal in args.items():
    if not varVal:
        del args[varName]
f(**args)

但最 Pythonic 的方法是使用 None 作为函数中的默认值:

f(a=None, b=None):
    a = 10 if a is None else a
    ...

然后打电话f(a, b)

于 2012-06-25T08:13:09.350 回答
1

默认情况下,Python 中的所有方法都采用可变参数

当你在方法的签名中定义一个参数时,你明确地使它成为必需的。在您的代码段中,您正在做的是给它一个默认值 - 而不是让它们成为可选的。

考虑以下:

>>> def func(a,b):
...    a = a if a else 0
...    b = b if b else 10
...    return a+b
...
>>> a = b = None
>>> func(a,b)
10
>>> a = 5
>>> b = 2
>>> func(a,b)
7
>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() takes exactly 2 arguments (0 given)

在此代码段中,两者a都是b必需的因为我没有定义任何默认值。它们不是可选的。

但是在您的代码段中,因为您在方法签名中为它们提供了默认值,所以它们看起来是可选的,但实际上它们只是分配了默认值。

>>> def func(a=0,b=10):
...    return a+b
...
>>> func()
10

您可以通过检查方法主体内的参数列表来确认这一点:

>>> def func(a=b,b=10):
...    print locals().keys()
...
>>> func()
['a', 'b']

让你的函数接受任意数量的参数的一种方法(换句话说,使它们都是可选的):

>>> def func(*args,**kwargs):
...    print len(args),args
...    print len(kwargs),kwargs
...
>>> func("hello","world",a=5,b=10)
2 ('hello', 'world')
2 {'a': 5, 'b': 10}
>>> func()
0 ()
0 {}
>>> func(1,2)
2 (1, 2)
0 {}
>>> func(a)
1 (5,)
0 {}
>>> func(foo="hello")
0 ()
1 {'foo': 'hello'}
于 2012-06-25T08:13:57.437 回答
0

为什么不将该逻辑传递给函数?

def func(a, b):
    a = a or 0
    b = b or 10
    return a + b
于 2012-06-25T08:08:12.400 回答
0

要回答您的字面问题:

func(a or 0, b or 10) 

编辑: 请参阅评论为什么这不能回答问题。

于 2012-06-25T08:35:21.457 回答
0

您可以使用三元 if-then 运算符将条件论证传递给函数 https://www.geeksforgeeks.org/ternary-operator-in-python/

例如,如果您想在传递之前检查密钥是否确实存在,您可以执行以下操作:

 
    def func(arg):
        print(arg)

    kwargs = {'name':'Adam')

    func( kwargs['name'] if 'name' in kwargs.keys() else '' )       #Expected Output: 'Adam'
    func( kwargs['notakey'] if 'notakey' in kwargs.keys() else '' ) #Expected Output: ''
 
于 2019-05-22T20:44:32.343 回答
-1

这可能有效:

def f(**kwargs):
    a = get(kwargs, 0)
    b = get(kwargs, 10)
    return a + b
于 2012-06-25T08:35:50.313 回答