2013-02-07 102 views
42

Python中有一种简单的方法来检查可选参数的值是否来自其默认值,或者因为用户在函数调用中显式地设置了它?Python:如何检查是否设置了可选函数参数

+2

为什么会这么重要? – Volatility

+9

因为我想在当然的函数中检查它:) – Matthias

+0

只需使用'None'作为默认值并检查它。如果你真的可以设置这个测试,你还可以排除用户显式传递调用默认行为的值的可能性。 –

回答

32

不是。标准的方法是使用用户不希望通过的默认值,例如,一个object实例:

DEFAULT = object() 
def foo(param=DEFAULT): 
    if param is DEFAULT: 
     ... 

通常你可以只使用None为默认值,如果它没有意义的值的用户想要通过。

另一种方法是使用kwargs

def foo(**kwargs): 
    if 'param' in kwargs: 
     param = kwargs['param'] 
    else: 
     ... 

然而,这是过于冗长,使得使用它的文件将不会自动包括param参数的功能变得更加困难。

+0

谢谢,我想我会坚持检查没有 – Matthias

+4

我也看到有几个人使用了省略号内建的地方需要这个地方,没有被认为是有效的输入。这与第一个例子基本相同。 – GrandOpener

2

我同意Volatility的评论。但你可以检查以下方式:

def function(arg1,...,**optional): 
    if 'optional_arg' in optional: 
     # user has set 'optional_arg' 
    else: 
     # user has not set 'optional_arg' 
     optional['optional_arg'] = optional_arg_default_value # set default 
+0

我相信一个可选参数就像'def func(optional = value)'不是'** kwargs' –

+0

这是有些开放的解释。具有默认值的参数与关键字参数之间的实际区别是什么?它们都使用相同的语法“keyword = value”表示。 – isedev

+0

我不同意,因为可选参数和'** kwargs'的目的有点不同。附:没有问题,大约-1 :)而我的-1对你来说是偶然的:) –

0

有点怪异的做法是:

,输出:

passed default 
z 
passed different 
b 
not passed 
z 

现在这一点,正如我所说,是相当畸形,但是它完成了这项工作。然而,这是不可读的,并且与ecatmursuggestion类似将不会被自动记录。

+1

你可能想要包含'check_f('z')'的行为,这也正如你所说,怪异。 –

+0

@ MichaelJ.Barber好点。你必须用* args做一些“魔术”。然而,我的观点是,这是可能的,但是现在是否需要通过默认值是一个糟糕的设计。 – dmg

7

以下函数装饰器explicit_checker为所有参数明确给出了一组参数名称。它将结果作为附加参数(explicit_params)添加到该函数中。只需执行'a' in explicit_params来检查是否明确给出了参数a

def explicit_checker(f): 
    varnames = f.func_code.co_varnames 
    def wrapper(*a, **kw): 
     kw['explicit_params'] = set(list(varnames[:len(a)]) + kw.keys()) 
     return f(*a, **kw) 
    return wrapper 

@explicit_checker 
def my_function(a, b=0, c=1, explicit_params=None): 
    print a, b, c, explicit_params 
    if 'b' in explicit_params: 
     pass # Do whatever you want 


my_function(1) 
my_function(1, 0) 
my_function(1, c=1) 
4

我有时使用通用唯一字符串(如UUID)。

import uuid 
DEFAULT = uuid.uuid4() 
def foo(arg=DEFAULT): 
    if arg is DEFAULT: 
    # it was not passed in 
    else: 
    # it was passed in 

这样,没有用户甚至可以猜测默认值,如果他们想这样我就可以非常自信,当我看到arg该值,它是不是在传递。

+0

这是一个黑客,但简洁而有效... – F1Rumors

+0

Python对象是引用,你可以使用'object()'而不是'uuid4()' - 它仍然是一个独特的_instance_,这是什么'是'检查 –

0

我已经看到了这个图案几次(如图书馆unittestpy-flagsjinja):

class Default: 
    def __repr__(self): 
     return "DEFAULT" 

DEFAULT = Default() 

...或等值的一行...:

DEFAULT = type('Default',(), { '__repr__': lambda x: 'DEFAULT' })() 

DEFAULT = object()不同,这有助于类型检查并在发生错误时提供信息 - 通常在错误消息中使用字符串表示("DEFAULT")或类名("Default")。

相关问题