在 Python 中注释函数

Image

我最近发布了一篇关于在 Typescript 中注释函数的博客。我刚刚完成了一些研究,对如何在 Python 中注释函数有了更多的了解,这篇博客将全部介绍如何注释 Python 函数,并提供与**上一篇博客**类似的示例。

您可以通过将 `python.analysis.typeCheckingMode` 设置为 `basic, standard, strict,` 之一来验证 **Visual Studio Code** 中的类型注释。`basic` 和 `standard` 选项不一定能确保您注释了函数和变量,但 `strict` 可以。

函数值

**这可能会让您感到震惊**,但您可以在 Python 中返回函数并将函数作为值传递。回调函数实际上是使用 `Callable` 类型注释的,其写法如下;

Callable[[argtype1, argtype2, argtype3], returnType]

例如,函数 `length(text: str) -> int` 将被注释为 `Callable[[str], int]`

例如;

JavaScript 中的此函数

function multiplier(factor){
    return value => factor * value
}

const n = multiplier(6)
n(8) // 48

在 Python 中可以这样写

def multiplier(factor):
    def inner(value):
        return value * factor
    return inner     

n = multiplier(6)
n(8) #48

我们可以创建一个名为“number”的“TypeAlias”,它是“int”和“float”的“Union”(字面意思);

from typing import TypeAlias, Union

number: TypeAlias = Union[int, float]

将参数作为**JavaScript 数字**来处理。

因此,**为了注释这个函数**,我们有;

def multiplier(factor: number) -> Callable[[number], number]:
    def inner(value: number) -> inner:
        return value * factor
    return inner

a = multiplier(4.5)
a(3) #13.5

泛型函数

经典的泛型函数示例是

def pick(array, index):
    return array[index]

pick([1,2,3], 2) #3

使用“TypeVar”我们现在可以创建通用的详细()。

from typing import TypeVar

T = TypeVar("T") # the argument and the name of the variable should be the same

**这样我们就有了**

from typing import TypeVar, Sequence

def pick(array: Sequence[T], index: int) -> T:
    return array[index]

print(pick([1,2,3,4], 2))

那么,自定义的“myMap”函数如何像 JavaScript 中的“map”一样工作呢?例如,我们有;

**记住**:Python 中的 `map()` 返回的是 `Iterable` 类型,而不是 `List` 类型

def myMap(array, fn):
    return map(fn, array)

def twice(n): return n * 2
print(myMap([1,2,3], twice))

我们可以使用 `Callable` 和 `TypeVar` 类型混合来注释此函数。**观察...**

from typing import TypeVar, Iterable, Callable

Input = TypeVar("Input")  # Input and "Input" must be the same
Output = TypeVar("Output")

def myMap(array: Iterable[Input], fn: Callable[[Input], Output]) -> Iterable[Output]:
    return map(fn, array)

def twice(n: int) -> int: return n * 2
print(myMap([1,2,3], twice))

或者我们可以为 `Callable` 函数添加**别名**

from typing import TypeVar, Iterable, Callable

Input = TypeVar("Input")
Output = TypeVar("Output")

MappableFunction = Callable[[Input], Output]

def myMap(array: Iterable[Input], fn: MappableFunction[Input, Output]) -> Iterable[Output]:
    return map(fn, array)

观察到“MappableFunction”采用了通用类型“Input”和“Output”,并将它们应用于“Callable[[Input], Output]”的上下文。

**花一点时间想想 myFilter 函数应该如何注释?**

如果你想到了这一点

from typing import Iterable, TypeVar, Callable

Input = TypeVar("Input")

def myFilter(array: Iterable[Input], fn: Callable[[Input], bool]) -> Iterable[Input]:
    return filter(fn, array)

**你说得对**

泛型类

我知道我不应该谈论类注释,但请给我一些时间来解释通用类。

如果你来自 **Typescript** 的世界,那么你就会这样定义它们

class GenericStore{
    stores: Array = []

    constructor(){
        this.stores = []
    }

    add(item: Type){
        this.stores.push(item)
    }
}

const g1 = new GenericStore(); //g1.stores: Array
g1.add("Hello") //only string are allowed

但在 Python 中,它们却相当不同且不方便。

  • 首先我们导入泛型类型,然后使它们成为泛型类的子类
  • **因此要在 Python 中重新创建这个 GenericStore 类**

    from typing import Generic, TypeVar
    from dataclasses import dataclass
    
    Type = TypeVar("Type")
    
    @dataclass
    class GenericStore(Generic[Type]):
    
        store: list[Type] = []
    
        def add(self, item: Type) -> None:
            self.store.append(item)
    
    g1 = GenericStore([True, False]) #g1.store: list[bool]
    g1.add(False) # only bool is allowed

    为什么我应该学习如何在 Python 中注释函数?

    正如我在前一篇博客中所说,它有助于构建更智能的类型系统,从而减少出现错误的可能性()。此外,在编写库时(),使用健壮的类型系统可以大大提高使用该库的开发人员的生产力()

    **如果您有任何疑问或本文中有错误,请在下面的评论中分享⭐**