繁体   English   中英

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

[英]Is it possible to type hint a lambda function?

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

def func(var1: str, var2: str) -> int:
    return var1.index(var2)

这表明该函数接受两个字符串,并返回一个整数。

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

func = lambda var1, var2: var1.index(var2)

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

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

您可以在 Python 3.6 及更高版本中使用PEP 526 variable annotations 您可以使用typing.Callable generic注释您分配lambda结果的变量:

from typing import Callable

func: Callable[[str, str], int] = lambda var1, var2: var1.index(var2)

这不会将类型提示信息附加到函数对象本身,仅附加到存储对象的命名空间,但这通常是类型提示所需的全部。

但是,您也可以只使用函数语句; lambda提供的唯一优点是您可以将简单表达式的函数定义放在更大的表达式中。 但是上面的 lambda 不是更大表达式的一部分,它只是赋值语句的一部分,将它绑定到一个名称。 这正是def func(var1: str, var2: str): return var1.index(var2)语句所能实现的。

请注意,您也不能单独注释*args**kwargs参数,因为Callable的文档指出:

没有语法来指示可选或关键字参数; 此类函数类型很少用作回调类型。

该限制不适用于具有__call__方法的 PEP 544协议 如果您需要对应该接受哪些参数进行表达定义,请使用它。 您需要 Python 3.8为 backport 安装typing-extensions项目

from typing_extensions import Protocol

class SomeCallableConvention(Protocol):
    def __call__(self, var1: str, var2: str, spam: str = "ham") -> int:
        ...

func: SomeCallableConvention = lambda var1, var2, spam="ham": var1.index(var2) * spam

对于lambda表达式本身,您不能使用任何注释(构建 Python 类型提示的语法)。 该语法仅适用于def函数语句。

来自PEP 3107 -函数注释

lambda 的语法不支持注解。 可以通过在参数列表周围使用括号来更改 lambda 的语法以支持注释。 但是, 决定不进行此更改,因为:

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

您仍然可以将注释直接附加到对象, function.__annotations__属性是可写字典:

>>> def func(var1: str, var2: str) -> int:
...     return var1.index(var2)
...
>>> func.__annotations__
{'var1': <class 'str'>, 'return': <class 'int'>, 'var2': <class 'str'>}
>>> lfunc = lambda var1, var2: var1.index(var2)
>>> lfunc.__annotations__
{}
>>> lfunc.__annotations__['var1'] = str
>>> lfunc.__annotations__['var2'] = str
>>> lfunc.__annotations__['return'] = int
>>> lfunc.__annotations__
{'var1': <class 'str'>, 'return': <class 'int'>, 'var2': <class 'str'>}

当然,当您想在类型提示上运行静态分析器时,并不是说像这样的动态注释会对您有所帮助。

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

from typing import Callable
is_even: Callable[[int], bool] = lambda x: (x % 2 == 0)

对于那些在编写代码时只是想快速访问智能感知的人来说,一个几乎破解方法是在 lambda 声明之前对参数进行类型注释,完成你的工作,然后才用参数隐藏它。

    x: YourClass
    map(lambda _ :  x.somemethod ...) # x has access to methods defined on YourClass

然后,紧接着:

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

这对我来说很好......

def fun()->None:
    def lam(i: int)->None:
        print("lam!", i)
    print("fun!")
    lam(1)
    lam(2)


fun()
lam()

印刷

fun!
lam! 1
lam! 2
Traceback (most recent call last):
  File "/home/jail/prog.py", line 16, in <module>
    lam()
NameError: name 'lam' is not defined

在 CPython 3.6.12 和 3.10.2 上测试

我非常不喜欢将 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"

不,这是不可能的,没有计划改变这一点,原因主要是语法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM