首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在协议上定义具有协变量返回类型的可调用属性?

如何在协议上定义具有协变量返回类型的可调用属性?
EN

Stack Overflow用户
提问于 2021-07-30 15:55:47
回答 2查看 534关注 0票数 1

通常可以理解,可调用的返回类型是co_variant。当使用可调用的_attribute定义类型时,我确实可以使返回类型成为通用的和协变量的:

代码语言:javascript
复制
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。

代码语言:javascript
复制
from typing import TypeVar, Callable, Protocol

R = TypeVar("R", covariant=True)

class Fails(Protocol[R]):
    attribute: Callable[[], R]
代码语言:javascript
复制
$ 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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-07-31 08:55:36

Protocol中,您尝试的内容显然是不可能的--参见佩普544中的以下内容

可变属性的协变子类型 拒绝,因为可变属性的协变量子类型不安全。考虑一下这个例子:

代码语言:javascript
复制
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

代码语言:javascript
复制
class Passes(Protocol[R]):
    @property
    def attribute(self) -> Callable[[], R]:
        pass

这通过了类型检查,但这是一个不灵活的解决方案。

如果您需要可变的协变量成员,那么Protocol并不是可行的。

票数 3
EN

Stack Overflow用户

发布于 2021-07-31 20:09:25

正如@Daniel所指出的,您不能通过协变量变量来参数化协议类型,因为它用于可变属性。

另一种选择是将变量分为两个(协变量和不变变量),并在两个协议(替换CallableProtocol)中使用它们。

代码语言:javascript
复制
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]
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68593867

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档