通常可以理解,可调用的返回类型是co_variant。当使用可调用的_attribute定义类型时,我确实可以使返回类型成为通用的和协变量的:
from typing import TypeVar, Callable, Generic, Sequence
from dataclasses import dataclass
R = TypeVar("R", covariant=True)
@dataclass
class Works(Generic[R]):
call: Callable[[], R] # returns an R *or subtype*
w: Works[Sequence] = Works(lambda: []) # okay: list is subtype of Sequence但是,对于Protocol来说,同样的情况并不适用。当我以同样的方式为该类型定义一个Protocol时,MyPy拒绝它-它坚持返回类型必须是_in_variant。
from typing import TypeVar, Callable, Protocol
R = TypeVar("R", covariant=True)
class Fails(Protocol[R]):
attribute: Callable[[], R]$ python -m mypy so_testbed.py --pretty
so_testbed.py:5: error: Covariant type variable "R" used in protocol where invariant one is expected
class Fails(Protocol[R]):
^
Found 1 error in 1 file (checked 1 source file)如何正确地为尊重Protocol协变性的具体类型定义R
发布于 2021-07-31 08:55:36
在Protocol中,您尝试的内容显然是不可能的--参见佩普544中的以下内容
可变属性的协变子类型 拒绝,因为可变属性的协变量子类型不安全。考虑一下这个例子:
class P(Protocol):
x: float
def f(arg: P) -> None:
arg.x = 0.42
class C:
x: int
c = C()
f(c) # Would typecheck if covariant subtyping
# of mutable attributes were allowed.
c.x >> 1 # But this fails at runtime最初的建议是出于实际原因允许这样做,但后来被拒绝了,因为这可能掩盖了一些很难发现的bug。
因为您的attribute是一个可变的成员-您不能让它在R方面是协变的。
一种可能的选择是用一种方法替换attribute:
class Passes(Protocol[R]):
@property
def attribute(self) -> Callable[[], R]:
pass这通过了类型检查,但这是一个不灵活的解决方案。
如果您需要可变的协变量成员,那么Protocol并不是可行的。
发布于 2021-07-31 20:09:25
正如@Daniel所指出的,您不能通过协变量变量来参数化协议类型,因为它用于可变属性。
另一种选择是将变量分为两个(协变量和不变变量),并在两个协议(替换、Callable和Protocol)中使用它们。
from typing import TypeVar, Callable, Protocol
R_cov = TypeVar("R_cov", covariant=True)
R_inv = TypeVar("R_inv")
class CallProto(Protocol[R_cov]):
def __call__(self) -> R_cov: ...
class Fails(Protocol[R_inv]):
attribute: CallProto[R_inv]https://stackoverflow.com/questions/68593867
复制相似问题