Python 类型提示:类型复杂类型的联合无法按预期与用户定义的类一起工作

问题描述 投票:0回答:1

我试图创建一个类型别名来匹配具有不同数量参数的 Callables,如下所示:

from typing import Callable

class C:
    pass

type F[T1, T2] = Callable[[T1], T2] | Callable[[T1, T1], T2]

b: Callable[[C], C] = lambda a, b: a + b # error
a: Callable[[C, C], C] = lambda a, b: a + b # error


# but:
c: F[C, C] = lambda a, b: a + b # no error

但如图所示,如果我用类

C
实例化它,它就不起作用,因为它也应该给出
c
的错误。对于 int 等内置类型,它确实可以按预期工作。

我正在使用最新版本的pyright(1.1.360)

是这个吗

  • 版权的限制?
  • 还是pyright的bug?
  • 或者是否需要做某事才能在课堂上进行这项工作?
type-hinting pyright python-3.12
1个回答
0
投票

我已将您的代码复制到在线游乐场,以便于访问实际错误和推断类型。

让我们按顺序考虑每个陈述:

  1. a
    类型检查的定义,除了类型
    C
    之外的预期错误之外,不支持
    +
    运算符(
    Operator "+" not supported for types "C" and "C"
    )。

    使用

    int
    时,此行不会产生错误,因为
    int
    确实实现了
    +
    运算符。这可能就是为什么您会看到“像 int 这样的内置类型”和类
    C
    之间的差异。

  2. b
    的定义使用
    Expression of type "(a: Unknown, b: Unknown) -> Unknown" is incompatible with declared type "() -> C"
    进行类型检查。

    这是预期的,因为带注释的指定了 0 个参数(

    Callable[[], C]
    中的第一个通用参数)。

  3. c
    的定义类型检查没有任何错误。

    这是出乎意料的,因为

    +
    运算符应该产生与
    a
    定义中相同的错误。不幸的是,Pyright 推断出两个参数的类型为
    Unknown
    ,其行为类似于
    Any
    ,这意味着
    +
    被假定为定义良好,并且操作结果为
    Unknown
    ,假定与
    C
    兼容。

    除此之外,函数类型确实与注释

    F[C, C]
    匹配,因为 lambda 的类型被推断为
    Callable[[Unknown, Unknown], Unknown]
    ,它与
    F[C, C]
    定义中的第二个选项(即
    Callable[[C, C], C]
    )兼容。


我相信

F
实际上代表了预期的类型,即“具有不同数量参数的可调用对象”。

这里可能让您感到困惑的是,Pyright 因使用

+
运算符而产生错误,该运算符与类型注释出现在同一行。然而,这些错误与注释本身无关。使用类型
int
时,这些错误也会消失,因为它支持
+
运算符。


我们可以进行一些实验来看看 Pyright 确实在做正确的事情:

  • __add__
    (运算符
    +
    )的定义添加到
    C
    以修复
    a
    中的错误:
def C:
    def __add__(self, other) -> "C":
        raise NotImplemented

a: Callable[[C, C], C] = lambda a, b: a + b # no error
  • 修改
    b
    的主体以匹配其类型注释:
b: Callable[[], C] = lambda: C() # no error
  • c
    的定义中显式指定参数类型,以暴露运算符
    +
    的错误:
def c_impl(a: C, b: C) -> C:
    return a + b # error: Operator "+" not supported for types "C" and "C"
c: F[C, C] = c_impl
  • 重写
    F
    的定义,不允许2参数函数产生
    c
    错误,并证明它正在检查参数的数量:
type F[T1, T2] = Callable[[T1], T2]

c: F[C, C] = lambda a, b: a + b # error
# Expression of type "(a: C, b: Unknown) -> Unknown" is incompatible with declared type "F[C, C]"
#  Type "(a: C, b: Unknown) -> Unknown" is incompatible with type "F[C, C]"
#    Function accepts too few positional parameters; expected 2 but received 1 
© www.soinside.com 2019 - 2024. All rights reserved.