协议实现类类型检查

问题描述 投票:0回答:1

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

鉴于以下代码,我希望

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 的逻辑似乎被破坏了。

python python-typing mypy
1个回答
2
投票

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

# 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"
© www.soinside.com 2019 - 2024. All rights reserved.