【问题标题】:Why can't non-default arguments follow default arguments?为什么非默认参数不能跟随默认参数?
【发布时间】:2013-05-31 17:36:55
【问题描述】:

为什么这段代码会抛出 SyntaxError?

  >>> def fun1(a="who is you", b="True", x, y):
...     print a,b,x,y
... 
  File "<stdin>", line 1
SyntaxError: non-default argument follows default argument

虽然以下代码运行时没有明显错误:

>>> def fun1(x, y, a="who is you", b="True"):
...     print a,b,x,y
... 

【问题讨论】:

  • 在python中定义函数def myfunction(position_arguments, *arguments, **keywords):` ....`时的结构是这样的
  • 当涉及到 KEYWORD-ONLY 参数时,没有明智的答案 - 为什么不能混合使用默认和非默认的仅关键字参数?它们是关键字,因此它们的顺序并不重要。这是一个任意限制。

标签: python


【解决方案1】:

所有必需的参数必须放在任何默认参数之前。仅仅因为它们是强制性的,而默认参数不是。从语法上讲,如果允许混合模式,解释器不可能决定哪些值与哪些参数匹配。如果参数未按正确顺序给出,则会引发 SyntaxError

让我们看看关键字参数,使用您的函数。

def fun1(a="who is you", b="True", x, y):
...     print a,b,x,y

假设它允许像上面那样声明函数, 然后通过上述声明,我们可以进行以下(常规)位置或关键字参数调用:

func1("ok a", "ok b", 1)  # Is 1 assigned to x or ?
func1(1)                  # Is 1 assigned to a or ?
func1(1, 2)               # ?

你将如何建议函数调用中的变量分配,默认参数将如何与关键字参数一起使用。

>>> def fun1(x, y, a="who is you", b="True"):
...     print a,b,x,y
... 

参考 O'Reilly - Core-Python
由于此函数使用语法正确的默认参数来进行上述函数调用。 关键字参数调用被证明对于能够提供无序位置参数很有用,但是,与默认参数结合使用,它们也可以用于“跳过”丢失的参数。

【讨论】:

  • 从语法上讲,如果允许混合模式,解释器不可能决定哪些值与哪些参数匹配。 Ruby 允许在默认参数之后使用非默认参数。 你将如何建议函数调用中的变量赋值只需使用func1(x=1, y=2)
  • 嗨@weakish,感谢您的评论,Python 确实有一个很好的方法来实现这一点,请搜索 *args 和 **kwargs
  • 嗨@Rahul Gautam 我很困惑。我认为**kwargs 不能使def fun1(a="who is you", b="True", x, y) 或类似的工作。如果使用def f(**kwargs),需要在body中处理默认值吗?
  • 你为什么写“从语法上讲,如果允许混合模式,解释器不可能决定哪些值与哪些参数匹配。”?我认为即使def foo(x=None, y) 被允许,PEP 3102 的算法也可以完全一样地工作。所以我仍然很好奇 为什么 Python 不允许这样做。是否有真正的根本原因,还是只是“我们不允许,因为我们不允许”。
  • 尝试def foo(a=1 ,b): called via foo(b=2) 并告诉我鼓舞人心的地方,我猜这不是在非默认值之前禁止默认值的原因..
【解决方案2】:
SyntaxError: non-default argument follows default argument

如果您允许这样做,默认参数将变得无用,因为您将永远无法使用它们的默认值,因为非默认参数在之后出现。

但是,在 Python 3 中,您可以执行以下操作:

def fun1(a="who is you", b="True", *, x, y):
    pass

这使得 xy 关键字只,所以你可以这样做:

fun1(x=2, y=2)

这行得通,因为不再有任何歧义。请注意,您仍然不能执行fun1(2, 2)(这将设置默认参数)。

【讨论】:

  • 仅关键字参数是 Python 3 的一个简洁功能。太糟糕了,将它们反向移植到 Python 2.6 和 2.7 的补丁只是 left to expire
  • 这不是真的:“如果您允许这样做,默认参数将变得无用,因为您将永远无法使用它们的默认值,因为非默认参数紧随其后。”示例: def foo(a=1 ,b): 通过 foo(b=2) 调用
【解决方案3】:

让我在这里澄清两点:

  • 首先非默认参数不应跟随默认参数,这意味着您不能在函数中定义 (a=b,c) 函数中定义参数的顺序是:
    • 位置参数或非默认参数,即 (a,b,c)
    • 关键字参数或默认参数,即 (a="b",r="j")
    • 仅关键字参数,即 (*args)
    • var-keyword 参数,即 (**kwargs)

def example(a, b, c=None, r="w" , d=[], *ae, **ab):

(a,b) 是位置参数

(c=none) 是可选参数

(r="w") 是关键字参数

(d=[]) 是列表参数

(*ae) 仅是关键字

(**ab) 是 var-keyword 参数

  • 现在次要的事情是如果我尝试这样的事情: def example(a, b, c=a,d=b):

保存默认值时参数未定义,Python计算 并在定义函数时保存默认值

c和d没有定义,不存在,发生这种情况时(只有在函数执行时才存在)

"a,a=b" 不允许在参数中。

【讨论】:

    【解决方案4】:

    必需的参数(没有默认值的参数),必须在开始时允许客户端代码只提供两个。如果可选参数在开头,那会很混乱:

    fun1("who is who", 3, "jack")
    

    在您的第一个示例中会做什么?最后,x 是“谁是谁”,y 是 3,a = “jack”。

    【讨论】:

      猜你喜欢
      • 2019-12-14
      • 1970-01-01
      • 1970-01-01
      • 2014-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-07
      • 2012-08-01
      相关资源
      最近更新 更多