【问题标题】:Reference argument in keyword argument关键字参数中的引用参数
【发布时间】:2018-06-10 03:03:07
【问题描述】:

有没有办法使用参数的值来动态设置关键字参数的默认值?我在想这样的事情:

def foo(lst, r = 0, l = len(lst)):    #I am referring to the "l = len(lst)" part
    print r, l


foo([1,2,3])

这给出了以下回溯:

Traceback (most recent call last):
  File "C:/Python27/quicksort.py", line 25, in <module>
    def foo(lst, r = 0, l = len(lst)):
NameError: name 'lst' is not defined

可以做类似的事情:

def foo(lst, r = 0, l = None):
    if l is None:
        l = len(lst)
    print r, l

但我希望有一个更优雅的解决方案。有人可以帮忙吗?

【问题讨论】:

  • 可能在函数体中将其缩短为l = l or len(lst)
  • 在定义函数时计算默认参数的值,而不是在调用它时。查看this question的答案
  • 有趣。在 Ruby 中,可选参数的默认参数值在调用方法时进行评估,并定义评估顺序(从左到右),以便 OP 的代码按预期工作。我从没想过 Python 是否会有所不同。
  • @cᴏʟᴅsᴘᴇᴇᴅ 这将不允许您通过非空列表传递l=0
  • @schwobaseggl 好点。

标签: python parameter-passing keyword-argument


【解决方案1】:

有没有办法使用参数的值来动态设置关键字参数的默认值?

很遗憾,没有。这可以用一个更简单的例子来展示:

>>> def func(a, b=a):
    return a, b

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    def func(a, b=a):
NameError: name 'a' is not defined

正如 cmets 中所说,Python 关键字参数值在函数被定义 时进行评估,但任何参数的值直到函数被调用 时才知道。因此,在 Python 中这样的事情根本不可行。

但是,您可以使用三元运算符使代码更紧凑:

def foo(lst, r=0, l=None):
    l = l if l is not None else len(lst)
    print(r, l)

【讨论】:

  • 好久没有答案了!节日快乐:-)
【解决方案2】:

默认参数在定义时计算,而不是在调用函数时。因此,其他参数尚不清楚,无法引用。您可以使用以下常见模式实现所需的行为:

def foo(lst, r=0, l=None):    
    if l is None:
        l = len(lst)
    # or shorter
    # l = len(lst) if l is None else l
    # or even shorter
    # l = (l, len(lst))[l is None]
    print r, l

【讨论】:

  • @ChristianDean Nah,这将导致无法将 0 显式传递给 l
  • 开枪!你的权利,我错过了。另外,如果 OP 可以确保 l 始终为正整数,则可以使用 l = l or (len)
  • @ChristianDean 没错,我以前经常这样做。现在,我更喜欢直言不讳。尤其是在工作中,我会一直使用双线if。这是最清楚的,每个人都立即知道发生了什么。
  • 是的,这可能是最安全的选择。事实上,使用orand 的错误是语言中添加条件表达式的原因之一。见PEP 308。无论如何,不​​错的答案 +1。
【解决方案3】:

但我希望有一个更优雅的解决方案。有人可以帮忙吗?

怎么样

def foo(lst, r=0, **kwargs):
    # Here we use `get`: dict.get(key, default = None)  
    print(r, kwargs.get('l', len(lst)))

def foo(lst, **kwargs):  
    print(kwargs.get('r', 0), kwargs.get('l', len(lst)))

def foo(lst, **kwargs):  
    r, l = kwargs.get('r', 0), kwargs.get('l', len(lst))
    print(r, l)

参考

*args and **kwargs?
https://www.tutorialspoint.com/python/dictionary_get.htm

【讨论】:

  • 谢谢,这是我还没有考虑过的解决方案!
  • @MarkusK 很高兴为您提供帮助!
【解决方案4】:

在这种情况下,我认为我们必须应用简单胜于复杂的原则,为什么不这样做:

def foo(lst, r = 0):
    print r, len(lst)

正如人们所说,没有办法在 Python 中做你想做的事,仅此而已......

【讨论】:

  • 如果 OP 想稍后传入 l,则此答案无效。
  • 我认为这不是被问到的。真正的答案是,至少目前在 Python 中无法做到这一点。
  • 我的意思是按照你的方式这个问题没有解决。我认为他们想要设置默认值的原因是他们以后可能想要传递其他东西。否则,您也不需要 r = 0 作为参数,只需返回 print 0, len(lst)
  • @Ipozo 我的代码是一个最小的示例(如 SO 推荐的那样)。我显然不是想简单地打印列表的长度......
  • 好吧,没问题,你想用你的lst做什么没问题(打印只是一个例子,我知道),重要的是你不能做你问的你想要这样做的方式,所以你必须在 foo 函数中处理 lst 。我的观点是:为什么要变得复杂?如果我的回答对你不好,我会理解的。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 2013-08-06
  • 2023-03-31
  • 2013-08-16
  • 1970-01-01
  • 2010-10-17
  • 2011-02-14
相关资源
最近更新 更多