簡體   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