关于python:正常参数与关键字参数

Normal arguments vs. keyword arguments

"关键字参数"与常规参数有何不同?难道所有参数都不能作为name=value而不是使用位置语法来传递吗?


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

在调用端,也就是其他注释者所提到的,您可以按名称指定一些函数参数。您必须在所有没有名称的参数(位置参数)之后提到它们,并且对于任何一点都没有提到的参数必须有默认值。

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

1
def my_function(arg1, arg2, **kwargs)

传递到此函数中的任何关键字参数都将放入名为kwargs的字典中。您可以在运行时检查此字典的键,如下所示:

1
2
3
4
5
6
def my_function(**kwargs):
    print str(kwargs)

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

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


最后一个语言特征是区别很重要。考虑以下功能:

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

*positional参数将存储传递给foo()的所有位置参数,不限制可以提供的数量。

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

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

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

当然,您可以同时使用这两种方法:

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

这些特性很少使用,但有时它们非常有用,了解哪些参数是位置参数或关键字很重要。


使用关键字参数与普通参数一样,只是顺序无关紧要。例如,下面两个函数调用是相同的:

1
2
3
4
5
def foo(bar, baz):
    pass

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


位置参数

他们面前没有关键词。订单很重要!

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

关键字参数

他们前面有关键词。它们可以是任意顺序的!

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

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

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

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


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

  • 按位置。位置参数没有关键字,而是先赋值。

  • 按关键字。关键字参数具有关键字,并在位置参数之后第二个指定。

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

    如果您不使用位置参数,那么——是的——您编写的所有内容都是关键字参数。

    当你调用一个函数时,你决定使用位置、关键字或混合。如果需要,可以选择执行所有关键字。我们中的一些人并没有做出这个选择并使用位置参数。


    我很惊讶,似乎没有人指出可以通过一个键控参数的字典来满足形式参数,就像这样。

    1
    2
    3
    4
    5
    6
    7
    8
    >>> 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
    >>>


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

    可选:(为"b"定义的默认值)

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

    必需(没有为"b"定义默认值):

    1
    2
    3
    4
    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'`

    如果您旁边有许多相似的参数,尤其是在同一类型的情况下,这会有所帮助,在这种情况下,我更喜欢使用命名参数,或者如果参数属于一起,则创建一个自定义类。


    我很惊讶没有人提到过这样一个事实:你可以混合使用位置和关键字参数,通过*args**kwargs(从这个站点)来做这种偷偷摸摸的事情:

    1
    2
    3
    4
    def test_var_kwargs(farg, **kwargs):
        print"formal arg:", farg
        for key in kwargs:
            print"another keyword arg: %s: %s" % (key, kwargs[key])

    这允许您使用任意的关键字参数,这些参数可能包含您不想预先定义的键。


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

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

    例子:

    1
    2
    3
    4
    5
    6
    7
    >>> 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 {}