python-3.x 如何用两个泛型编写函数并强制一个泛型实现另一个泛型

mo49yndu  于 2023-04-22  发布在  Python
关注(0)|答案(2)|浏览(113)

目标是接收任何两个泛型,并让类型检查器强制第二个泛型实现第一个泛型。
如果有人试图使用未实现IType泛型的TType泛型调用此函数,则此C#代码段将引发编译时错误。

public static void Foobar<IType, TType>() where IType : TType { }

我正在尝试用Python编写等效的代码,其中mypy或pyright类型检查器将捕获此错误。
这就是我迄今为止所尝试的:

T = TypeVar("T")
T2 = TypeVar("T2", bound=T) # Seems we cannot bind to another TypeVar

示例代码:

from typing import Protocol, TypeVar, runtime_checkable

T = TypeVar("T")

@runtime_checkable
class IBar(Protocol):
    def hello(self) -> None:
        ...

class Bar:
    def hello(self) -> None:
        return None

@runtime_checkable
class IFoo(Protocol):
    def foo(self) -> None: ...

class Foo:
    def foo(self) -> None: ...

def foobar(a: type[T], b: type[T]) -> T:
    instance = b()
    assert isinstance(instance, a)
    return instance

a = foobar(IBar, Bar) # should pass
b = foobar(IBar, Foo) # should fail
c = foobar(IFoo, Foo) # should pass
d = foobar(IFoo, Bar) # should fail

Mypy给我这个错误,这不是预期的错误:
错误:只能在需要“类型[IBar]”的地方给出具体类
Pyright没有给出任何错误,但预期的错误是让它抱怨Foo没有实现IBar协议。

6ojccjat

6ojccjat1#

使用TypeVar的绑定参数检查提供的示例是否是绑定类型的子类型,如python文档中所述。它需要在TypeVar示例声明之前定义IBar,如下所示:

@runtime_checkable
class IBar(Protocol):
    def hello(self) -> None:
        ...

T = TypeVar("T", bound=IBar)

然后,在下面一行中:

b = foobar(IBar, Foo)

“Foo”将在这个问题中突出显示(使用vscode,并将“类型检查模式”设置为strict)

Argument of type "Type[Foo]" cannot be assigned to parameter "b" of type "Type[T@foobar]" in function "foobar"
  Type "IBar" cannot be assigned to type "Foo"
bxgwgixi

bxgwgixi2#

试试这个。

from typing import TypeVar, Protocol

T = TypeVar('T', bound=Protocol)

class IBar(Protocol):
    def hello(self) -> None:
        ...

def foobar[T: IBar](arg: T) -> None:
    pass

class Bar:
    def hello(self) -> None:
        pass

class Foo:
    pass

foobar(Bar())  # This is valid
foobar(Foo())  # This will raise a type error because Foo does not implement IBar

相关问题