我正在与 StrEnums 的类型缩小作斗争
总结我的问题,我有一些抽象基类
from abc import ABC, abstractmethod
from enum import StrEnum
class Animal(ABC):
@staticmethod
@abstractmethod
def speak(animal_type: StrEnum):
...
以及派生类,每个类都有自己的 StrEnum:
class FrogType(StrEnum):
frog = "frog"
toad = "toad"
class Frog(Animal):
@staticmethod
def speak(animal_type: FrogType):
print(f"{animal_type} goes ribbit")
以下代码按预期工作:
Frog.speak(FrogType.frog) # "frog goes ribbit"
和枚举似乎兼容:
print(isinstance(FrogType.frog, FrogType)) # True
print(isinstance(FrogType.frog, StrEnum)) # True
但是 MyPy 不认为这是有效的:
# python3.11 -m mypy frog.py
frog.py:16: error: Argument 1 of "speak" is incompatible with supertype "Animal"; supertype defines the argument type as "StrEnum" [override]
frog.py:16: note: This violates the Liskov substitution principle
frog.py:16: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
Found 1 error in 1 file (checked 1 source file)
这似乎是一个有效的类型缩小,所以我必须注释一些错误的东西。正确的解决方案是什么?
您可以使用泛型代替
StrEnum
来避免此问题。下面定义 AnimalType
,使其具有 StrEnum
的界限:
from abc import ABC, abstractmethod
from enum import StrEnum
from typing import Generic, TypeVar
AnimalType = TypeVar("AnimalType", bound=StrEnum)
class Animal(ABC, Generic[AnimalType]):
@staticmethod
@abstractmethod
def speak(animal_type: AnimalType):
...
class FrogType(StrEnum):
frog = "frog"
toad = "toad"
class Frog(Animal[FrogType]):
@staticmethod
def speak(animal_type: FrogType):
print(f"{animal_type} goes ribbit")
print(isinstance(FrogType.frog, FrogType)) # True
print(isinstance(FrogType.frog, StrEnum)) # True
希望这有帮助!