是否可以输入提示lambda函数?

Nat*_*ill 42 python lambda

目前,在Python中,函数的参数和返回类型可以是类型提示,如下所示:

def func(var1: str, var2: str) -> int:
    return var1.index(var2)
Run Code Online (Sandbox Code Playgroud)

表示该函数接受两个字符串,并返回一个整数.

但是,这种语法与lambdas非常混淆,它看起来像:

func = lambda var1, var2: var1.index(var2)
Run Code Online (Sandbox Code Playgroud)

我已经尝试在参数和返回类型上添加类型提示,我无法找出一种不会导致语法错误的方法.

是否可以输入提示lambda函数?如果没有,是否有计划暗示lambda,或任何原因(除了明显的语法冲突)为什么不呢?

Mar*_*ers 41

不,您不能使用带有lambda表达式的注释(构建Python类型提示的语法).语法仅适用于typing.Callable函数语句.

PEP 3107 - 功能注释:

lambda的语法不支持注释.通过在参数列表周围要求括号,可以更改lambda的语法以支持注释.然而,决定不进行此更改,因为:

  • 这将是一个不相容的变化.
  • 无论如何,Lambda都是绝育的.
  • lambda始终可以更改为函数.

您仍然可以将注释直接附加到对象,该*args属性是可写字典:

from typing import Callable

func: Callable[[str, str], int] = lambda var1, var2: var1.index(var2)
Run Code Online (Sandbox Code Playgroud)

当然,当您想要在类型提示上运行静态分析器时,并不是像这些动态注释会帮助您.

  • @GuidovanRossum:因为这是一个*不同*问题的答案。:-) 这里的问题是如何将类型提示应用于 lambda,以提供与定义函数相同的结果。尽管如此,我还是会添加一个部分来说明为什么您可能不想使用 lambda。 (9认同)
  • 如果答案是 `func: Callable[[str, str], int] = lambda var1, var2: var1.index(var2)` 那么为什么不是一个更好的答案 `def func(var1: str, var2: str) -> int: 返回 var1.index(var2)`??? (7认同)
  • 不,从字面上看,答案应该是“不,这是不可能的,没有计划改变这一点,原因主要是语法上的——定义一个命名函数并对其进行注释很容易。” 我还注意到,如果 lambda 隐藏在大型调用或数据结构中,建议的解决方法(创建具有特定 Callable 类型的变量)并不是很有帮助,因此它在任何意义上都不比定义函数“更好”。(我认为这“更糟糕”,因为 Callable 表示法的可读性不是很好。) (6认同)
  • @GuidovanRossum:那我可以邀请你写下你自己的答案吗?凭借您作为语言之父的特定地位,只要有时间,您的答案很容易超越这个答案,并且您可以准确地写下您认为应该在其中包含的内容。 (4认同)
  • 为了定义类型化函数变量以及默认值(可能是 noop),我认为上面的答案是合理的(尽管由于 Callable 语法而丑陋)代码 (3认同)
  • 关于 Guido,我不同意这不是问题的正确答案。我认为这个答案完美地回答了如何注释 lambda 的局限性。我更喜欢这个答案而不是“这是不可能的” (3认同)
  • 该解决方案还分散了人们的注意力,因为它看起来像是在定义一个具有特定 Callable 类型的“变量”,可以在其生命周期内为其分配不同的 lambda。这与定义函数不同(如果您重新定义或重新分配 def 但不是 Callable 类型的变量,至少 mypy 会犹豫),并且远离最初的问题“我只想要一个带有类型注释的 lambda”。我继续声称,在这种情况下,保留 lambda 形式而不是 def 形式没有任何好处。(我想说即使没有类型注释。) (2认同)

jan*_*jan 37

从Python 3.6开始,你可以(参见PEP 526):

from typing import Callable
is_even: Callable[[int], bool] = lambda x: (x % 2 == 0)
Run Code Online (Sandbox Code Playgroud)

正如用户cz所指出的,这与注释非匿名函数的签名不同.如果您在上面的示例中传递str变量,Mypy v0.620不会抱怨is_even.

  • 这实际上并没有注释lambda本身:你不能像注释函数那样从lambda对象中检索这些注释 (3认同)
  • 带有 Python 3.7 的 mypy 0.701 正确地进行了类型检查:`is_even('x')` 会导致类型错误。 (3认同)
  • @stenci is_even函数是一个Callable,需要一个int参数,因此x是int。 (2认同)

小智 13

我非常不喜欢将 lambda 函数分配给标识符(请参阅Is it pythonic:naming lambdas)。如果您仍然想这样做,这里已经有答案了。

如果你不这样做,只是想让类型检查器做他们的事情,答案是typing.cast

from typing import cast, Callable

cast(Callable[[int], int], lambda x: x + 1)("foo")
# error: Argument 1 has incompatible type "str"; expected "int"
Run Code Online (Sandbox Code Playgroud)


rtv*_*iii 12

对于那些在编写代码时只想快速访问智能感知的人来说,一种近乎黑客的做法是在 lambda 声明之前对参数进行类型注释,完成您的工作,然后才使用该参数来隐藏它。

x: YourClass
map(lambda _:  x.somemethod ...)  # x has access to methods defined on YourClass
Run Code Online (Sandbox Code Playgroud)

然后,就在之后:

x: YourClass # can remove or leave
map(lambda x:  x.somemethod, ListOfYourObjects)  # inner x now shadows the argument
Run Code Online (Sandbox Code Playgroud)

  • 这是一种令人不愉快的黑客方法,但我正在使用它...... (2认同)