【问题标题】:Protocol implementation class type check协议实现类类型检查
【发布时间】:2021-10-19 15:42:03
【问题描述】:

我无法弄清楚这是否可能。

鉴于以下代码,我希望mypy 报告两种情况的错误:

from dataclasses import dataclass
from typing import Generic, Protocol, Type, TypeVar

T = TypeVar("T")

class MyProto(Protocol):
    attr: str

class Impl:
    attr: int  # wrong type on purpose for this example

# This util class is an attempt to illustrate what I'm trying to achieve, an answer may very well
# indicate changes to it, if required, to make it work as desired.
@dataclass
class Util(Generic[T]):
   proto: T
   impl: Type[T]

# Case 1
# The following is type checked, and correctly reports the error when the implementation does not
# satisfy the protocol.
C: Type[MyProto] = Impl 

# Case 2
# Where as this is accepted regardless, but I'd like it to report error in case Impl does not
# satisfy MyProto.
util = Util(MyProto, Impl)

示例输出:

$ python -m mypy t.py
t.py:22:20: error: Incompatible types in assignment (expression has type "Type[Impl]", variable has type "Type[MyProto]")  [assignment]
    C: Type[MyProto] = Impl 
                       ^
Found 1 error in 1 file (checked 1 source file)

用例是,能够动态注册实现及其支持的协议,同时仍然进行静态类型检查。希望这是有道理的。

更新

好的,所以我发现我上面的内容应该可以正常工作,只要 Protocol 有一个可以实际工作的类型表示。现在,T 被推断为object 而不是MyProto,因为这是传递给Util() 的两种类型的最小公分母。但是,如果我明确声明 T 应该是 MyProto,我会更接近:

util = Util[MyProto](MyProto, Impl)

几乎给了我想要的东西:

[...]
t.py:42:22: error: Argument 1 to "Util" has incompatible type "Type[MyProto]"; expected "MyProto"  [arg-type]
    util = Util[MyProto](MyProto, Impl)
                         ^
t.py:42:31: error: Argument 2 to "Util" has incompatible type "Type[Impl]"; expected "Type[MyProto]"  [arg-type]
    util = Util[MyProto](MyProto, Impl)
                                  ^

参数1的错误是错误的,期望的类型是正确的,参数的报告类型是错误的,应该只是MyProto或者协议类应该用类型系统来表示。

关于参数 2 的错误是正确的,如果我修复 Impl 使其与协议匹配,它就会消失。

因此,在协议方面,缺乏适当的类型表示以及确定两种类型之间 LCD 的逻辑似乎被打破了。

【问题讨论】:

标签: python type-hinting mypy typechecking python-typing


【解决方案1】:

有趣的是,我会在此处发布问题后首先找到答案(花了一整天的时间来解决这个问题,直到我最终被推向正确的方向)。

# tweaked Util class, thus:
@dataclass
class Util(Generic[T]):
   proto: Type
   impl: Type[T]

# then using it as such, with an explicit generic type:
util = Util[MyProto](MyProto, Impl)
t.py:27:31: error: Argument 2 to "Util" has incompatible type "Type[Impl]"; expected "Type[MyProto]"  [arg-type]
    util = Util[MyProto](MyProto, Impl)
                                  ^
Found 2 errors in 1 file (checked 1 source file)

然而,这不是最优雅的,所以如果有人在构造Util 实例时弄清楚如何避免重复MyProto,将不胜感激。

还注意到,如果我传入 Impl 的实例,而不仅仅是类,我会从 mypy 收到更好的错误消息。

t.py:27:31: error: Argument 2 to "Util" has incompatible type "Impl"; expected "MyProto"  [arg-type]
    util = Util[MyProto](MyProto, Impl())
                                  ^
t.py:27:31: note: Following member(s) of "Impl" have conflicts:
t.py:27:31: note:     attr: expected "str", got "int"

【讨论】:

  • 考虑到我正在尝试做的事情的运行时方面,我将在这种情况下使用 ABC 而不是协议类。
猜你喜欢
  • 2015-04-14
  • 2022-01-21
  • 1970-01-01
  • 2015-05-25
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
  • 1970-01-01
相关资源
最近更新 更多