Python 位置参数和关键字参数

2024-10-06 11:26:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在阅读mercurial的源代码,在commands.py中找到了这样一个func def:

def import_(ui, repo, patch1=None, *patches, **opts):
    ...

在python中,positional参数必须放在关键字参数之前。但是这里,patch1是一个关键字参数,后面跟着一个位置参数*patches。为什么这样可以?


Tags: pyimportnoneui参数源代码defrepo
3条回答

可能您有点混淆了函数定义和函数调用语法。

patch1不是关键字arg,而是分配了默认参数值的位置arg。

*patches是参数列表,而不是位置参数。


请从官方教程中查看此部分:

现在让我以这个函数为例总结一下要点:

def f1(a1, a2, a3=None, *args, **kwargs):
  print a1, a2, a3, args, kwargs

函数定义

有许多参数是由名称(a1a2a3)显式定义的,其中a3将由None默认初始化,如果在调用期间未提供。参数a1a2需要在该函数的任何有效调用中提供。

可以使用附加参数调用函数,这些参数将出现在字典kwargs(由关键字提供)或列表args(不由关键字提供)中。 如果函数定义中不存在argskwargs,则除了函数定义中为函数调用显式命名的参数外,调用方将不允许添加更多参数。

在函数定义中,首先需要指定不带默认初始值设定项的显式参数,其次是带默认初始值设定项的显式参数,第三是参数列表,最后是关键字参数字典。

函数调用

有多种方法可以调用函数。例如,以下调用将产生相等的结果:

f1(1, 2)       # pass a1 and a2 as positional arguments
f1(a2=2, a1=1) # pass a1 and a2 as keyword arguments
f1(1, a2=2)    # pass a1 as positional argument, a2 as keyword argument

也就是说,函数参数可以通过其位置(位置参数或非关键字参数)或其指定的名称(关键字参数)来解析。

调用函数时,需要将非关键字参数放在第一位,最后是关键字参数,例如

# demonstrate how some additional positional and keyword arguments are passed
f1(1, 2, 3, 4, 5, 6, 7, a4=8, a5=9, a6=10)
# prints:
# 1 2 3 (4, 5, 6, 7) {'a5': 9, 'a4': 8, 'a6': 10}

现在,不符合函数定义中指定参数列表的位置参数将附加到参数列表*args,不符合函数定义中指定参数列表的关键字参数将插入关键字参数字典**kwargs

因为如果关键字参数的位置是明确的,那么将关键字传递给该参数是可选的。注意:

>>> def f(ui, patch1=None, *patches, **opts):
...     print patch1
... 
>>> f(1, 2)
2
>>> f(1, patch1='a', 3)
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
>>> f(1, 'a', 3)
a

如您所见,省略patch1的键将该参数呈现为非关键字参数,因此不会触发SyntaxError异常。


编辑:moooeeep在他的回答中说

"patch1 is not a keyword arg, it's a positional arg with a default argument value assigned."

这并没有错,但以下IMO的案例说明了为什么这种定义是含糊不清的:

>>> def f(ui, p1=None, p2=None, *patches, **opts):
...    print p1, p2
... 
>>> f(1, 'a', 'b', 3)  #p2 is a positional argument with default value?
a b
>>> f(1, p2='b')  #p2 is a keyword argument?
None b

啊!

只要看看PEP 3102它似乎也与this有某种联系。

总的来说,补丁和opt是用来接受变量参数的,但后者是用来接受关键字参数的。关键字参数作为字典传递,其中作为variable positional arguments would be wrapped as tuples

从你的例子

def import_(ui, repo, patch1=None, *patches, **opts):

u1,repo and patch1之后的任何位置参数都将以元组的形式封装在补丁中。变量位置参数后面的任何关键字参数都将通过opts包装为字典对象。

另一件重要的事情是,调用方有责任确保不违反条件non-keyword arg after keyword arg

因此,违反此规则的内容将引发语法错误。。

例如

像这样的电话

 import_(1,2,3,test="test")
 import_(1,2,3,4,test="test")
 import_(1,2,3,4,5)
 import_(1,2,patch1=3,test="test")

是有效的,但是

import_(1,2,3,patch1=4,5)

会引发语法错误SyntaxError: non-keyword arg after keyword arg

在第一个有效案例中import_(1,2,3,test="test")

u1 = 1, repo = 2, patch1 = 3, patches = () and opts={"test":"test"}

在第二种有效情况下import_(1,2,3,patch1=4,test="test")

u1 = 1, repo = 2, patch1 = 3 , patches = (4) and opts={"test":"test"}

在第三种有效情况下import_(1,2,3,4,5)

u1 = 1, repo = 2, patch1 = 3 , patches=(4,5), and opts={}

在第四种有效情况下import_(1,2,patch1=3,test="test")

u1 = 1, repo = 2, patch1 = 3 , patches=(), and opts={"test":"test"}
you can use patch1 as a keywords argument but doing so you cannot wrap any variable positional arguments within patches

相关问题 更多 >