有没有一种方法可以向函数传递可选参数?

137

在Python中,调用函数时是否有一种传递可选参数的方法,并且在函数定义中只有在“仅当可选参数被传递时”才有相应的代码呢?

5个回答

116

Python 2 documentation, 7.6. Function definitions提供了几种方法来检测调用者是否提供了可选参数。

首先,您可以使用特殊的形式参数语法*。如果函数定义有一个由单个*前导的形式参数,则Python会使用任何未与前面的形式参数匹配的位置参数填充该参数(作为元组)。 如果函数定义具有由**前导的形式参数,则Python会使用任何未与前面的形式参数匹配的关键字参数填充该参数(作为字典)。 函数的实现可以检查这些参数的内容以获取所需的任何“可选参数”。

例如,这是一个名为opt_fun的函数,它接受两个位置参数x1x2,并查找另一个名为“optional”的关键字参数。

>>> def opt_fun(x1, x2, *positional_parameters, **keyword_parameters):
...     if ('optional' in keyword_parameters):
...         print 'optional parameter found, it is ', keyword_parameters['optional']
...     else:
...         print 'no optional parameter, sorry'
... 
>>> opt_fun(1, 2)
no optional parameter, sorry
>>> opt_fun(1,2, optional="yes")
optional parameter found, it is  yes
>>> opt_fun(1,2, another="yes")
no optional parameter, sorry

其次,你可以为某个参数提供一个默认值,比如None,这是调用者永远不会使用的值。如果参数采用了这个默认值,你就知道调用者没有指定该参数。而如果参数采用了非默认值,你就知道它来自于调用者。

7
positional_parameters 是一个元组,而 keyword_parameters 是一个字典。 - Cees Timmerman
Python如何区分前面带有*的形式参数(这被称为什么?)和关键字参数?据我所了解,关键字参数是在函数调用中使用=运算符指定的(因此opt_fun(1,2, optional="yes")为预期但不一定需要参数option提供了一个关键字参数"yes")。 - Minh Tran
另一方面,我理解 * 前的形式参数仅仅是“调用者提供的不对应于任何关键字参数的位置参数”。例如,在 opt_fun(1,2, "blah", 3.14, mykey="yes", myyear="2018") 中,"blah"3.14* 前的形式参数,因为它们位于两个位置参数和使用 = 符号的参数之间。生成的元组 positional_parameter 将是二元组:("blah", 3.14)。这正确吗? - Minh Tran
@MinhTran,在Stack Overflow中,评论中提问并不是获得答案的最佳方式。更好的方法是点击大蓝色的“提问”按钮,并将您的请求写成一个“问题”,其他人可以“回答”。但是为了帮助您,a)请注意我写的是“parameter”,而不是“parameters”,用于“preceded by *”。该语言只允许参数列表中有一个*identifier。b)请阅读https://docs.python.org/2/reference/compound_stmts.html#function-definitions,c)请阅读https://docs.python.org/2/reference/expressions.html#calls。抱歉,在此评论中字符已经用完。 - Jim DeLaHunt

84

谢谢,有没有办法在代码中将该参数的默认值指定为另一个变量? - user1795998
default_value=100; def my_func(mandatory_argument, optional_argument_with_default_value=default_value): ...default_value=100; 表示默认值为 100;def my_func(mandatory_argument, optional_argument_with_default_value=default_value): ... 表示定义了一个名为 my_func 的函数,该函数有一个必选参数 mandatory_argument 和一个可选参数 optional_argument_with_default_value,如果不传入该参数,则使用默认值 default_value - warvariuc
这似乎展示了如何使用可选参数,但没有展示如何测试是否传递了一个参数,这是OP所问的。 - Mawg says reinstate Monica
4
在大多数情况下,这比Jim的解决方案更简单明了。如果您将默认值设置为None,则可以检查参数是否已传递。唯一一个Jim的解决方案更好的情况是在必须区分传递None作为参数和根本不传递参数的情况。 - Arnon Axelrod

19
def op(a=4,b=6):
    add = a+b
    print add

i)op() [o/p: will be (4+6)=10]
ii)op(99) [o/p: will be (99+6)=105]
iii)op(1,1) [o/p: will be (1+1)=2]
Note:
 If none or one parameter is passed the default passed parameter will be considered for the function. 

1
有没有办法只传递第二个参数(b)而不传第一个参数(a)? - Djidiouf
5
@Djidiouf 是的,有 op(b=2) - Jürg W. Spaak

7

如果你想给参数设置默认值,在括号中赋值,例如 (x=10)。但重要的是必须先传递必需参数,再传递默认值。

例如:

(y, x=10)

但是

(x=10, y)是错误的。


谢谢,有没有办法在代码中将该参数的默认值指定为另一个变量? - user1795998
жҳҜзҡ„пјҢдҪ еҸҜд»ҘдҪҝз”Ё*argе’Ң**kargдҪңдёәеҮҪж•°еҸӮж•°гҖӮеңЁи°·жӯҢдёҠжҗңзҙўеҚіеҸҜгҖӮ - sumit
这似乎展示了如何使用可选参数,但没有展示如何测试是否传递了一个可选参数,这正是OP所问的。 - Mawg says reinstate Monica

2

您可以通过使用永远不会传递给函数的某些内容来为可选参数指定默认值,并使用is运算符进行检查:

class _NO_DEFAULT:
    def __repr__(self):return "<no default>"
_NO_DEFAULT = _NO_DEFAULT()

def func(optional= _NO_DEFAULT):
    if optional is _NO_DEFAULT:
        print("the optional argument was not passed")
    else:
        print("the optional argument was:",optional)

只要您不执行func(_NO_DEFAULT),就可以准确地检测参数是否已传递,与接受的答案不同,您不必担心**符号的副作用。
# these two work the same as using **
func()
func(optional=1)

# the optional argument can be positional or keyword unlike using **
func(1) 

#this correctly raises an error where as it would need to be explicitly checked when using **
func(invalid_arg=7)

只需执行 _NO_DEFAULT = object() - Aran-Fey
增加两行代码以提供更好的内省是值得的。这样,如果您运行help(func),您将更清楚地了解参数如何被解释,如果没有明确传递参数,则会有更好的理解。 - Tadhg McDonald-Jensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接