Python 静态类型提示/检查 Iterable[AnyStr] 与 Iterable[str] 之间的不匹配 |可迭代[字节]

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

我遇到了这个静态类型提示不匹配(与 Pyright):

from __future__ import annotations
from typing import AnyStr, Iterable


def foo(i: Iterable[AnyStr]):
    return i


def bar(i: Iterable[str] | Iterable[bytes]):
    return i


def baz(i: Iterable[str | bytes]):
    return i


def main():
    s = ['a']

    # makes sense to me
    baz(foo(s))  # allowed
    foo(baz(s))  # not allowed

    # makes sense to me
    baz(bar(s))  # allowed
    bar(baz(s))  # not allowed

    bar(foo(s))  # allowed
    foo(bar(s))  # nope -- why?

Iterable[AnyStr]
Iterable[str] | Iterable[bytes]
有什么区别?

它们不应该是“等价的”吗? (除了

AnyStr
指的是上下文中的单一一致类型)

更具体地说:输入提示以下内容的正确方法是什么?

import random
from typing import Iterable, AnyStr

def foo(i: Iterable[AnyStr]):
    return i

def exclusive_bytes_or_str():  # type-inferred to be Iterator[bytes] | Iterator[str]
    if random.randrange(2) == 0:
        return iter([b'bytes'])
    else:
        return iter(['str'])

foo(iter([b'bytes']))          # fine
foo(iter(['str']))             # fine
foo(exclusive_bytes_or_str())  # same error
python python-typing covariance contravariance
1个回答
2
投票

转述来自 erictraut@githubanswer

这并不是受约束的 TypeVar 的真正预期用途。我建议使用

@overload
代替:

@overload
def foo(i: Iterable[str]) -> Iterable[str]: ...
@overload
def foo(i: Iterable[bytes]) -> Iterable[bytes]: ...

def foo(i: Iterable[AnyStr]) -> Iterable[AnyStr]:
    return i

因为:

类型 Iterable[str] | Iterable[bytes] 不可分配给类型 Iterable[AnyStr]。受约束类型变量需要与其约束之一相匹配,而不是多个约束。当一个类型变量被“解决”时,它需要被另一个(通常是具体的)类型替换。如果允许 foo(bar(s)),则 AnyType@foo 类型变量将解析为什么类型?如果解决了输入 str | bytes,那么 foo 的具体返回类型将是 Iterable[str |字节]。这显然是错误的。

© www.soinside.com 2019 - 2024. All rights reserved.