【问题标题】:Is it possible to reference function parameters in Python's function annotation?是否可以在 Python 的函数注释中引用函数参数?
【发布时间】:2018-07-11 11:36:53
【问题描述】:

我想说

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

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

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

【问题讨论】:

  • 那个名字没有定义;不可能,函数注释是在定义函数的范围内评估的,而不是在函数本身的范围内。 postponed evaluation 可以做到这一点,但一般来说,generic types 可以更好地解决这些问题 - f 接受 T 类型的参数并返回 T 类型。

标签: python annotations type-systems pep


【解决方案1】:

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 将返回一个str,这使得它与注解不一致。诚然,这个例子是人为的,但从语言设计的角度来看,这是需要小心的。

相反,正如 jonrsharpe 所提到的,引用 generic types 提到的参数(如 jonrsharpe)的最佳方式通常是使用 type variables

这可以使用typing.TypeVar 类来完成。

from typing import TypeVar

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

这意味着静态检查器不需要实际访问param 的类型,只需在检查时检查是否有办法同时考虑param 和相同类型的返回值。我说考虑相同的类型,因为您有时只会断言它们都实现相同的abstract base class/接口,例如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) 的情况下,它只会返回list,而不是像List[T] 那样的列表。所以使用type(param) 实际上会丢失信息,而不是添加它。

因此,最好还是坚持使用type variablesgeneric types

TL;DR

  1. 由于variable shadowingtype(param) 可能会导致注释不一致。
  2. 由于有时在考虑系统类型时,您会根据 接口(Python 中的 abstract base classes)而不是具体类型来考虑,因此最好依赖 ABC 和 @987654330 @
  3. 使用 type(param) 可能会丢失由泛型提供的信息

【讨论】:

    【解决方案2】:

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

    注解必须是有效的表达式,在定义函数时不会引发异常(但请参阅下面的前向引用)。

    注释应保持简单,否则静态分析工具可能无法解释这些值。例如,动态计算的类型不太可能被理解。 (这是一个有意含糊的要求,具体的包含和排除可能会根据讨论的需要添加到此 PEP 的未来版本中。)

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

    【讨论】:

      猜你喜欢
      • 2011-09-25
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-18
      • 2016-07-20
      • 2020-01-28
      相关资源
      最近更新 更多