我一直无法弄清楚这是否可能。
鉴于以下代码,我希望
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)
用例是,能够动态注册实现及其支持的协议,同时仍然进行静态类型检查。希望这是有道理的。
更新
好吧,所以我发现,只要协议具有实际有效的类型表示,我上面的内容就应该按原样工作。现在,
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 的逻辑似乎被破坏了。
有趣的是,在在这里发布问题后,我首先会找到答案(花了一整天的时间来解决这个问题,直到我最终被推向正确的方向)。
# 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)
然而,这不是最优雅的,因此,如果有人在构造
MyProto
实例时弄清楚如何避免重复 Util
,将不胜感激。
还注意到,如果我传入
mypy
的实例,而不仅仅是类,我会从 Impl
收到更好的错误消息。
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"