是否可以在Python的函数注解中引用函数参数?

Is it possible to reference function parameters in Python's function annotation?

我想说

def f(param) -> type(param): return param

但我得到 NameError: name 'param' is not defined。这里的关键是 return 类型是函数参数的函数。我浏览了 https://www.python.org/dev/peps/pep-3107/,但没有看到任何关于包含有效注释表达式的内容的准确描述。

我会接受一个解释为什么 确切地说 这目前不可能的答案,即它不适合当前的注释范例还是存在技术问题?

我们来看看PEP-484 - Type Hints # Acceptable type hints

Annotations must be valid expressions that evaluate without raising exceptions at the time the function is defined (but see below for forward references).

Annotations should be kept simple or static analysis tools may not be able to interpret the values. For example, dynamically computed types are unlikely to be understood. (This is an intentionally somewhat vague requirement, specific inclusions and exclusions may be added to future versions of this PEP as warranted by the discussion.)

我想说你的方法很有趣,可能对静态分析有用。但是如果我们接受 PEP 作为当前注释范例的解释来源,突出显示的文本解释了为什么 return 类型不能在函数被 调用时动态定义 .

type(param) 方法存在一些问题。

首先,正如 Oleh 在他的回答中提到的,所有注释在 函数定义 时必须有效。在像您这样的示例中,由于 variable shadowing.

,您可能会遇到问题
param = 10

def f(param) -> type(param):
    return param

f('a')

由于变量 param 的类型为int,函数的注解实质上读作f(param: Any) -> int。因此,当您传入 参数 param 且值为 'a' 时,这意味着 f 将 return 一个 str ,这使得它与注释不一致。不可否认这个例子是人为的,但从语言设计的角度来看,这是需要小心的。

相反,正如 jonrsharpe 提到的,通常最好的方式是引用 generic types of parameters (as jonrsharpe) mentioned is with type variables

这可以使用 typing.TypeVar class.

from typing import TypeVar

def f(param: T) -> T:
    return param

这意味着静态检查器不需要实际访问 param 的类型,只需在检查时检查是否有一种方法可以同时考虑 param 和 return相同类型的值。我说考虑相同的类型,因为您有时只会断言它们都实现了相同的 abstract base class/interface, like numbers.Real.

然后可以在泛型类型中使用 typevars

from typing import List, TypeVar

T = TypeVar('T')

def total(items: List[T]) -> List[T]:
    return [f(item) for item in items]

使用类型变量和泛型可能会更好,因为它添加了额外的信息并允许更多的灵活性(如 numbers.Real 示例中所述)。例如,使用 List[T] 的能力非常重要。在您使用 type(param) 的情况下,它只会 return list,而不是像 List[T] 那样的 列表。所以使用 type(param) 实际上会 丢失信息 ,而不是添加它。

因此,最好坚持使用 type variables and generic types

TL;DR:

  1. 由于 variable shadowingtype(param) 可能导致注释不一致。
  2. 因为有时在考虑系统类型时,您会根据 接口 (abstract base classes in Python) instead of concrete types, it can be better to rely on ABC's and type variables
  3. 使用 type(param) 可能会 丢失信息 将由仿制药提供。