使用可选参数调用方法的最pythonic方法是什么?

时间:2022-06-02 22:19:51

Let's say I have a method with a few optional parameters.

假设我有一个带有一些可选参数的方法。

def foo(a, b=1, c=2, d=3)

def foo(a,b = 1,c = 2,d = 3)

How do I go about calling it so that if my variables are None or empty strings the defaults are used?

如何调用它以便如果我的变量为None或空字符串,则使用默认值?

Conditionals like the following seems like a horrible solution:

像下面这样的条件似乎是一个可怕的解决方案:

if b and not c and d:
    foo(myA, b = myB, d = myD)
elif b and not c and not d:
    ...

In Java I'd jump for a factory, but it seems like that's what defaults are supposed to avoid in this case.

在Java中,我会跳转到一个工厂,但看起来这就是默认情况下应该避免的情况。

5 个解决方案

#1


7  

I would change foo so it replaces empty values with default ones.

我会改变foo,所以它用默认值替换空值。

def foo(a, b=None, c=None, d=None):
    if not b: b = 1
    if not c: c = 2
    if not d: d = 3

Note that this will treat all "false-y" values as defaults, meaning not only None and '' but also 0, False, [], etc. Personally I would tighten the interface up and use None and only None as a default value.

请注意,这会将所有“false-y”值视为默认值,不仅意味着None和'',还包括0,False,[]等。我个人会收紧界面并使用None,只有None作为默认值。

def foo(a, b=None, c=None, d=None):
    if b is None: b = 1
    if c is None: c = 2
    if d is None: d = 3

#2


3  

Though I agree that changing the method is a better idea, here's an alternative that changes the calling part by using a dict of arguments, which is filtered and then unpacked:

虽然我同意更改方法是一个更好的主意,但这里有一个替代方法,通过使用参数的dict来更改调用部分,该参数将被过滤然后解压缩:

d = {'b': myB, 'd': myD}
foo(myA, **{k: d[k] for k in d if d[k]})

Of course if d[k] can be replaced by if d[k] not in {None, ''} for example, which has a slightly different meaning (as pointed out by others).

当然,如果d [k]可以被替换为if d [k]而不是{None,''},例如,其具有略微不同的含义(如其他人所指出的)。

#3


2  

If you want to catch ONLY None and '':

如果你想只捕获无和'':

def foo(a, b, c, d):
    blacklist = set([None, ''])
    if b in blacklist:
        b = 1
    if c in blacklist:
        c = 2
    if d in blacklist:
        d = 3

If you want to catch all values v such that bool(v) is False, then:

如果你想捕获所有值v使得bool(v)为False,那么:

def foo(a, b, c, d):
    b = b or 1
    c = c or 2
    d = d or 3

Or you could decorate the function with another function that does the assertions for you (which may or may not be overkill, based on your use case)

或者您可以使用另一个为您执行断言的函数来装饰该函数(根据您的用例,这可能是也可能不是过度杀伤)

#4


2  

You could call a function that filters out the variables you don't want passed down

您可以调用一个函数来过滤掉您不想传递的变量

def arg_filter(**kw):
    return dict((k,v) for k,v in kw.items() if v not in (None, ''))

foo(**arg_filter(a=1,b=None,c=''))

#5


1  

Not fully tested, but should act as a base:

没有经过充分测试,但应作为基础:

import inspect
from functools import wraps

def force_default(f):
    @wraps(f)
    def func(*args, **kwargs):
        ca = inspect.getcallargs(f, *args, **kwargs)
        da = inspect.getargspec(f)
        dv = dict(zip(reversed(da.args), reversed(da.defaults)))
        for k, v in ca.iteritems():
            if v is None or v == '':
                ca[k] = dv[k]
        return f(**ca)
    return func

@force_default
def foo(a, b=1, c=2, d=3):
    print a, b, c, d

foo(6, '', None, 'rabbit!')
# 6 1 2 rabbit!

#1


7  

I would change foo so it replaces empty values with default ones.

我会改变foo,所以它用默认值替换空值。

def foo(a, b=None, c=None, d=None):
    if not b: b = 1
    if not c: c = 2
    if not d: d = 3

Note that this will treat all "false-y" values as defaults, meaning not only None and '' but also 0, False, [], etc. Personally I would tighten the interface up and use None and only None as a default value.

请注意,这会将所有“false-y”值视为默认值,不仅意味着None和'',还包括0,False,[]等。我个人会收紧界面并使用None,只有None作为默认值。

def foo(a, b=None, c=None, d=None):
    if b is None: b = 1
    if c is None: c = 2
    if d is None: d = 3

#2


3  

Though I agree that changing the method is a better idea, here's an alternative that changes the calling part by using a dict of arguments, which is filtered and then unpacked:

虽然我同意更改方法是一个更好的主意,但这里有一个替代方法,通过使用参数的dict来更改调用部分,该参数将被过滤然后解压缩:

d = {'b': myB, 'd': myD}
foo(myA, **{k: d[k] for k in d if d[k]})

Of course if d[k] can be replaced by if d[k] not in {None, ''} for example, which has a slightly different meaning (as pointed out by others).

当然,如果d [k]可以被替换为if d [k]而不是{None,''},例如,其具有略微不同的含义(如其他人所指出的)。

#3


2  

If you want to catch ONLY None and '':

如果你想只捕获无和'':

def foo(a, b, c, d):
    blacklist = set([None, ''])
    if b in blacklist:
        b = 1
    if c in blacklist:
        c = 2
    if d in blacklist:
        d = 3

If you want to catch all values v such that bool(v) is False, then:

如果你想捕获所有值v使得bool(v)为False,那么:

def foo(a, b, c, d):
    b = b or 1
    c = c or 2
    d = d or 3

Or you could decorate the function with another function that does the assertions for you (which may or may not be overkill, based on your use case)

或者您可以使用另一个为您执行断言的函数来装饰该函数(根据您的用例,这可能是也可能不是过度杀伤)

#4


2  

You could call a function that filters out the variables you don't want passed down

您可以调用一个函数来过滤掉您不想传递的变量

def arg_filter(**kw):
    return dict((k,v) for k,v in kw.items() if v not in (None, ''))

foo(**arg_filter(a=1,b=None,c=''))

#5


1  

Not fully tested, but should act as a base:

没有经过充分测试,但应作为基础:

import inspect
from functools import wraps

def force_default(f):
    @wraps(f)
    def func(*args, **kwargs):
        ca = inspect.getcallargs(f, *args, **kwargs)
        da = inspect.getargspec(f)
        dv = dict(zip(reversed(da.args), reversed(da.defaults)))
        for k, v in ca.iteritems():
            if v is None or v == '':
                ca[k] = dv[k]
        return f(**ca)
    return func

@force_default
def foo(a, b=1, c=2, d=3):
    print a, b, c, d

foo(6, '', None, 'rabbit!')
# 6 1 2 rabbit!