普通参数与关键字参数

332

“关键字参数”与普通参数有何不同?难道不是所有的参数都可以使用 name=value 来代替位置语法吗?


6
你可能还想阅读PEP 3102——他们正在Python 3中整理一些这方面的内容。请参见:http://www.python.org/dev/peps/pep-3102/ - Ben Hoyt
是否存在默认值与此无关(除非您需要为其传递一个值),对吧? - mk12
2
@Ben Hoyt 在下面添加了一个答案,涵盖了 Python 3 中必需的关键字参数。 - Christophe Roussy
10个回答

398

有两个相关的概念,都称为“关键字参数”。

在调用函数的一侧,正如其他评论者所提到的那样,您可以通过名称指定一些函数参数。您必须在没有名称(位置参数)的所有参数之后提及它们,并且对于任何未完全提及的参数必须有默认值

另一个概念是在函数定义方面:您可以定义一个按名称接收参数的函数--甚至不必指定这些名称是什么。这些是纯关键字参数,不能以位置方式传递。 语法是

def my_function(arg1, arg2, **kwargs)

你传递到这个函数里的任何关键字参数将被放置在一个名为kwargs的字典中。你可以在运行时检查这个字典的键,例如:

def my_function(**kwargs):
    print str(kwargs)

my_function(a=12, b="abc")

{'a': 12, 'b': 'abc'}

6
+1 和 accepted:你是唯一一个谈到了位置参数和关键字参数两种类型的人,其他人要么认为我在谈论第一个参数类型,要么认为我在谈论第二个参数类型(但他们的帖子还是不错的)。谢谢! - mk12
47
措辞不清:通常在调用方说“参数(parameters)”,而在被调用方说“参数(arguments)”。 - glglgl
3
еҸӮж•°еҗҚеҝ…йЎ»жҳҜkwargsеҗ—пјҹжҲ–иҖ…жҲ‘еҸҜд»Ҙе°Ҷе…¶йҮҚе‘ҪеҗҚдёәзұ»дјјoptionsзҡ„еҗҚз§°пјҲdef my_function(arg1, arg2, **options)пјүпјҹ - Bruce Sun
4
名称可以是任意的,但当没有更合适的名称时,“kwargs”是惯用语。 - Matt Zimmerman
2
我认为这里解释的第二个概念在技术上被称为任意关键字参数。 - Anshul Dahiya
根据下面 @Eli Grey 的说法,你似乎也可以只使用名称来调用它,完全忽略“位置”的参数,例如:my_function(x='kw-x', y='kw-y', arg2='pos-a2', arg1='pos-a1') - Ed Randall

216

还有一项语言特性,区别非常重要。考虑以下函数:

def foo(*positional, **keywords):
    print "Positional:", positional
    print "Keywords:", keywords

*positional参数将存储传递给foo()的所有位置参数,不限定数量。

>>> foo('one', 'two', 'three')
Positional: ('one', 'two', 'three')
Keywords: {}

keywords参数将存储任何关键字参数:

>>> foo(a='one', b='two', c='three')
Positional: ()
Keywords: {'a': 'one', 'c': 'three', 'b': 'two'}

当然,你可以同时使用两者:

>>> foo('one','two',c='three',d='four')
Positional: ('one', 'two')
Keywords: {'c': 'three', 'd': 'four'}

这些功能很少被使用,但偶尔它们非常有用,了解哪些参数是定位参数或关键字参数是很重要的。


4
非常好的回答!只是需要注意,如果我们更改函数定义为def foo(arg1, *positional, **keywords):,则必需的位置参数可以在*positional**keywords之前传递。这里的arg1是位置参数且是必需的。请注意,回答中的位置参数表示可选的、可变数量的位置参数。 - shaffooo
2
是的,很好的答案。另外一点:如果你调用函数 foo(bar=True),你可以使用 bar = keywords.pop('bar') 或者 bar = keywords.pop('bar', None) 来获取值。对于默认值,请使用 bar = keywords.pop('bar', False) - oHo

129

使用关键字参数与使用普通参数相同,唯一的区别是顺序不重要。例如,下面的两个函数调用是相同的:

def foo(bar, baz):
    pass

foo(1, 2)
foo(baz=2, bar=1)

7
谢谢这个。有一个非常有用的功能,我可以同时将关键字参数指定为位置参数,并且将位置参数指定为关键字参数。 - Luke Davis
1
注意:这在使用位置参数(PEP 570引入并在Python 3.8中被接受)时是不可能的。pow的签名为pow(x, y, z=None, /),具有位置参数(参数列表中的/表示所有前面的参数都是位置参数)。随着这个变化,pow(x=5, y=3)会导致Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: pow() takes no keyword arguments。请参阅https://www.python.org/dev/peps/pep-0570/。 - joseville

52

位置参数

它们之前没有关键字。顺序很重要!

func(1,2,3, "foo")

关键字参数

它们在前面有关键字。它们可以以任意顺序出现!

func(foo="bar", baz=5, hello=123)

func(baz=5, foo="bar", hello=123)

你还需要知道,如果你使用默认参数并忽略插入关键字,那么顺序就很重要了!

def func(foo=1, baz=2, hello=3): ...
func("bar", 5, 123)

9
依我之见,第三个例子(默认参数)不是很清楚。我认为你讲的是当一个或多个参数声明了默认值,并且调用使用位置标记法,但提供的参数数目比声明的参数数目少时会发生什么。然而,你的例子中有三个已声明的参数和三个在调用中给出的参数,因此默认值根本没有起作用!你是否打算省略第三个参数,例如 func("bar", 5)?然后说明 hello 得到了它的默认值 3 - ToolmakerSteve

27

有两种方法可以为函数参数分配参数值,都被使用。

  1. 按位置。 位置参数没有关键字,并首先分配。

  2. 按关键字。 关键字参数具有关键字,并在位置参数之后第二次分配。

请注意,可以选择使用位置参数。

如果不使用位置参数,那么 - 是的 - 您写的一切最终都将成为关键字参数。

调用函数时,您可以决定使用位置、关键字或混合。 如果您愿意,可以选择使用所有关键字。 我们中的一些人不会做出这个选择,而是使用位置参数。


1
哦,我一直在想参数的事情,但实际上是参数(也就是传递的内容)。谢谢! - mk12

25

我很惊讶没有人指出可以这样传递一个键控参数字典,满足形式参数。

>>> def func(a='a', b='b', c='c', **kwargs):
...    print 'a:%s, b:%s, c:%s' % (a, b, c)
... 
>>> func()
a:a, b:b, c:c
>>> func(**{'a' : 'z', 'b':'q', 'c':'v'})
a:z, b:q, c:v
>>> 

11
对于一种有用的技巧,我给出一个赞成。如果不使用 **kwargs,你的论点会更加清晰。这将证明即使在一个固定参数数量的简单函数定义中,也可以提供一个字典。也就是说,在定义中不需要任何花哨的东西。然后,你可以添加第二个例子,其中包含 **kwargs 在定义中,并展示如何通过它来获得字典中的额外项。 - ToolmakerSteve
1
我在各种库的源代码中看到过这种情况,感到很困惑。谢谢你澄清了这个问题! - Craig Labenz
3
上面的第四个正式参数 - **kwargs 是必要的,如果您曾经使用包含除'a'、'b'和'c'以外键的字典调用func。 - Eduardo
对我来说,print 'a:%s, b:%s, c:%s' % (a, b, c) 会出现语法错误,但是 print('a:%s, b:%s, c:%s' % (a, b, c)) 可以正常工作。这是 Python 版本的问题吗?无论如何,感谢您提供这个见解,直到现在我一直在使用更加笨拙的 print('a:{}, b:{}, c:{}'.format(a, b, c)) - Axel Bregnsbo
这表明默认参数可以在不传入的情况下使用,也可以被覆盖/指定。但我认为第二个例子func(kwargs)的传递是非常冗余的,因为我们可以简单地使用位置参数调用>>> func('z','q','v')。此外,如果您像这样做>>> func('p',{'a':'z','b':'q','c':'v'}),您将得到一个关于参数'a'的多个值的错误。 - Leon Chang

24

使用Python 3,您可以同时拥有必需和非必需的关键字参数


可选: (对于参数'b'定义了默认值)

def func1(a, *, b=42):
    ...
func1(value_for_a) # b is optional and will default to 42

必需的(参数“b”未定义默认值):

def func2(a, *, b):
    ... 
func2(value_for_a, b=21) # b is set to 21 by the function call
func2(value_for_a) # ERROR: missing 1 required keyword-only argument: 'b'`

如果您有许多相似的参数需要传递,特别是它们属于同一类型,那么可以使用命名参数或者创建自定义类来处理这种情况。


3
所需的变量非常有用。它督促我们按名称提供参数,而不提供默认值,这通常是没有意义的。 - TNT
默认值看起来很好,可以帮助你节省时间,但从长远来看,默认值可能会成为一个麻烦。 - Christophe Roussy

11
我很惊讶没有人提到这个事实,即您可以混合使用位置和关键字参数来使用*args**kwargs来做一些聪明的事情(从这个网站)。
def test_var_kwargs(farg, **kwargs):
    print "formal arg:", farg
    for key in kwargs:
        print "another keyword arg: %s: %s" % (key, kwargs[key])

这将允许您使用任意关键字参数,这些参数可能具有您不想事先定义的键。


0

我正在寻找一个使用类型注释的默认kwargs示例:

def test_var_kwarg(a: str, b: str='B', c: str='', **kwargs) -> str:
     return ' '.join([a, b, c, str(kwargs)])

例子:

>>> print(test_var_kwarg('A', c='okay'))
A B okay {}
>>> d = {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', c='c', b='b', **d))
a b c {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', 'b', 'c'))
a b c {}

0

只需补充/添加一种定义函数调用时未分配关键字参数的默认值的方法:

def func(**keywargs):
if 'my_word' not in keywargs:
    word = 'default_msg'
else:
    word = keywargs['my_word']
return word

通过以下方式调用:

print(func())
print(func(my_word='love'))

你将获得:

default_msg
love

在Python中了解更多关于*args**kwargs的知识: https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3


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