【问题标题】:python positional args and keyword argspython位置参数和关键字参数
【发布时间】:2011-12-13 08:13:26
【问题描述】:

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

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

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

【问题讨论】:

  • 你解决了吗?如果有,最好选择使您解决问题的答案为“已接受”,并为所有有用的答案投票(如果您还没有这样做!)。 :)
  • 对不起,我这几天一直很忙。我现在将阅读您的答案并选择一个。谢谢大家:)

标签: python func function


【解决方案1】:

看看PEP 3102,它似乎与this有某种关系。

总而言之,patch 和 opts 可以接受可变参数,但后者是接受关键字参数。关键字参数作为字典传递,其中variable positional arguments would be wrapped as tuples

从你的例子

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

u1,repo and patch1 之后的任何位置参数都将被包装为补丁中的元组。变量位置参数之后的任何关键字参数都将通过 opts 包装为 Dictionary 对象。

另一个重要的事情是,调用者有责任确保不违反条件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

【讨论】:

  • 感谢您的示例和参考,我想我得到了答案。 python的论点太灵活了,在这个问题之前我还不太了解。
【解决方案2】:

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

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

【讨论】:

  • 我觉得这个定义有点模棱两可(虽然不是不正确的)。请参阅我的答案中关于原因的编辑。
  • 看我的例子,你可以使用 patch1 作为关键字参数,只要它后面没有位置参数。
【解决方案3】:

因为如果它的位置是明确的,将键传递给关键字参数可以是可选的。观察:

>>> 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 异常。


编辑: moooeeeep 在他的回答中说

“patch1 不是关键字 arg,它是一个位置 arg,并分配了默认参数值。”

这没有错,但下面的 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

HTH!

【讨论】:

  • 是的......在我看来,这是运行时的歧义,而不是定义时的歧义。由于 OP 关注函数定义I was describing the function definition。但我承认,这是一个很好的注意点。
【解决方案4】:

我相信当调用函数时:

function(arg1="value")

这将使用“关键字”参数,但是当定义函数的接口时:

def function(arg1="value"):

您正在定义一个“默认值”。 ()

所以回答你的问题;在位置参数之后有一个默认值是完全正常的,在关键字之前调用一个带有非关键字参数的函数也是如此。

另请注意,在调用函数时,您不能在关键字后面加上非关键字参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-21
    • 2023-03-31
    • 2018-12-12
    • 2017-05-21
    • 1970-01-01
    • 2020-11-18
    • 2017-06-29
    • 1970-01-01
    相关资源
    最近更新 更多