如何解决静态类型枚举的抽象方法
从抽象超类枚举 Action
和 Activity
有继承的枚举:
-
ActivityA
可以在其上执行ActionA
;和 -
ActivityB
可以对其执行ActionB
。
如何在抽象 action
方法的 perform
方法的 Activity
参数中添加类型声明,以便 MyPy 尊重继承或哪个操作适用于哪个活动?
from abc import ABC,ABCMeta,abstractmethod
from enum import EnumMeta,IntEnum
class ABCEnumMeta(EnumMeta,ABCMeta):
...
class Action(ABC,IntEnum,metaclass=ABCEnumMeta):
...
class ActionA(Action):
start = 1
stop = 2
class ActionB(Action):
start = 1
pause = 2
resume = 3
complete = 4
fail = 5
class Activity(ABC,metaclass=ABCEnumMeta):
@abstractmethod
def perform(
self: "Activity",action,# <- This line
) -> str:
...
class ActivityA(Activity):
this = 1
that = 2
def perform(
self: "ActivityA",action: ActionA,) -> str:
return f"A: {action.name} {self.name}"
class ActivityB(Activity):
something = 1
another = 2
def perform(
self: "ActivityB",action: ActionB,) -> str:
return f"B: {action.name} {self.name}"
print( ActivityB.something.perform(ActionB.pause) )
print( ActivityA.this.perform(ActionA.stop) )
print( ActivityB.another.perform(ActionA.start) )
print( ActivityA.that.perform(ActionB.fail) )
正在使用的 mypy.ini
设置文件是:
[mypy]
disallow_any_expr = True
disallow_any_decorated = True
disallow_any_explicit = True
disallow_any_generics = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
MyPy 的输出是:
test_enum.py:26: error: Function is missing a type annotation for one or more arguments
test_enum.py:26: error: Type of decorated function contains type "Any" ("Callable[[Activity,Any],str]")
test_enum.py:56: error: Argument 1 to "perform" of "ActivityB" has incompatible type "ActionA"; expected "ActionB"
test_enum.py:57: error: Argument 1 to "perform" of "ActivityA" has incompatible type "ActionB"; expected "ActionA"
(最后两个错误是预期的。)
在这种情况下,我通常会使用泛型并定义:
A = TypeVar("A",bound=Action)
class Activity(ABC,Generic[A],action A,) -> str:
...
class ActivityA(Activity[ActionA]):
...
class ActivityB(Activity[ActionB]):
...
但是,当您尝试添加泛型时,Enum
类会引发异常。
如何解决这个问题以正确定义抽象方法的参数类型?
解决方法
部分解决方案(因为 Enum
不能有 Generic
混合)是在抽象父方法中使用超类型 Action
(而不是尝试使用子通过泛型类型):
class Activity(ABC,IntEnum,metaclass=ABCEnumMeta):
@abstractmethod
def perform(
self: "Activity",action: Action,) -> str:
...
这将给出错误:
test_enum.py:36: error: Argument 1 of "perform" is incompatible with supertype "Activity"; supertype defines the argument type as "Action"
test_enum.py:36: note: This violates the Liskov substitution principle
test_enum.py:36: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
test_enum.py:47: error: Argument 1 of "perform" is incompatible with supertype "Activity"; supertype defines the argument type as "Action"
test_enum.py:47: note: This violates the Liskov substitution principle
test_enum.py:47: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
test_enum.py:56: error: Argument 1 to "perform" of "ActivityB" has incompatible type "ActionA"; expected "ActionB"
test_enum.py:57: error: Argument 1 to "perform" of "ActivityA" has incompatible type "ActionB"; expected "ActionA"
可以使用 # type: ignore[override]
显式 locally silenced 附加错误:
class ActivityA(Activity):
this = 1
that = 2
def perform( # type: ignore[override]
self: "ActivityA",action: ActionA,) -> str:
return f"A: {action.name} {self.name}"
class ActivityB(Activity):
something = 1
another = 2
def perform( # type: ignore[override]
self: "ActivityB",action: ActionB,) -> str:
return f"B: {action.name} {self.name}"
一旦这些错误在本地被消除,那么输出就是两个预期的错误:
test_enum.py:56: error: Argument 1 to "perform" of "ActivityB" has incompatible type "ActionA"; expected "ActionB"
test_enum.py:57: error: Argument 1 to "perform" of "ActivityA" has incompatible type "ActionB"; expected "ActionA"
虽然这清楚地表明抽象父方法应该在参数中采用 Action
类型,但它并没有从抽象父类中表明子类应该期待一个特定的子类型(作为泛型会允许)。因此,这只是部分解决方案;更好的解决方案是“修复” Enum
类(或子类 Enum
)以允许 Generic
混合。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。