接受应与协议匹配的枚举器类型的正确类型是什么? 我的意思是枚举器应该在协议中定义成员
这是一个简化的代码示例。
from typing import Protocol
from enum import Enum
class MyProto(Protocol):
item1: int
item2: int
def check_item1( e: MyProto, value:int):
return e.item1 == value
class MyEnum(int, Enum):
item1 = 0
item2 = 1
other_item_not_in_protocol = 2
check_item1( MyEnum, 0 ) #<-- pyright complains about everything :
Pyright 抱怨
# Argument of type "type[MyEnum]" cannot be assigned to parameter "e" of type "MyProto" #in function "check_item1"
# "item1" is invariant because it is mutable
# "item1" is an incompatible type
# "item1" must be defined as a ClassVar to be compatible with protocol
# "Literal[MyEnum.item1]" is incompatible with "int"
# "item2" is invariant because it is mutable
# "item2" is an incompatible type
# "item2" must be defined as a ClassVar to be compatible with protocol
# "Literal[MyEnum.item2]" is incompatible with "int" [reportArgumentType]
Mypy 也抱怨:
# error: Argument 1 to "check_item1" has incompatible type "type[MyEnum]"; expected # "MyProto" [arg-type]
# Found 1 error in 1 file (checked 1 source file)
您需要三件事来进行此类型检查。
首先,使用
item1
将 item2
和 @property
设为只读:
class MyProto(Protocol):
@property
def item1(self) -> int:
...
@property
def item2(self) -> int:
...
引用规格:
默认情况下,上面定义的协议变量被认为是可读可写的。要定义只读协议变量,可以使用(抽象)属性。
其次,使用
ClassVar
明确指出 Enum
成员是类级别的,而不是实例级别的变量(尽管在运行时已经是这种情况):
class MyEnum(int, Enum):
item1: ClassVar = 0
item2: ClassVar = 1
# Other members do not need ClassVar
other_item_not_in_protocol = 2
这就是第三个要求的来源:Pyright 通过了这个,但 mypy 没有。
我不确定哪一个是正确的。虽然规范确实规定
ClassVar
是区分类级和实例级属性所必需的,但没有任何地方说 Protocol
内定义的实例级属性必须由单个特定类的所有实例共享该类的实例被认为与相关的 Protocol
兼容。
我可能是错的。这是我检查过的所有页面:
为了区分协议类变量和协议实例变量,应按照 PEP 526 的规定使用特殊的
注释。默认情况下,上面定义的协议变量被认为是可读和可写的。要定义只读协议变量,可以使用(抽象)属性。ClassVar
特别是,无值表示法
允许注释 should 在a: int
或__init__
中初始化的实例变量。__new__