我正在AnyStr
上编写一个泛型类,因此允许bytes
或str
。
class MyObject(Generic[AnyStr]):
...
在这个类的(多个(方法中,我想根据类型参数构造空字节或空字符串对象b''
或''
。我该怎么做?
您应该有一个基类,该基类具有应用于str
和bytes
的共享方法,这些方法利用了公共行为(例如,str
和bytes
都有长度,或者str
和bytes
都是可索引的(,以及两个子类,为特定行为提供实现。为了强制子类提供这些特定的行为(使得mypy
可以假设对其特定方法的调用将在基类中成功(,您可以在基类中生成等效的@abstractmethod
。
这一切看起来是这样的:
from abc import abstractmethod, ABC
from typing import AnyStr, Generic, final
class MyObject(ABC, Generic[AnyStr]):
@classmethod
@abstractmethod
def empty(cls) -> AnyStr:
pass
def __init__(self, data: AnyStr):
self.data: AnyStr = data
# Example shared method.
def is_empty(self) -> bool:
# Assume that for the sake of the example we can't do `len(self.data) == 0`, and that we need
# to check against `empty()` instead.
return self.data == self.__class__.empty()
class MyStr(MyObject[str]):
@classmethod
@final
def empty(cls) -> str:
return ""
class MyBytes(MyObject[bytes]):
@classmethod
@final
def empty(cls) -> bytes:
return b""
我们将empty()
作为类方法而不是实例方法,因为它不依赖于具有特定数据的实例来知道空的str
/bytes
是什么样子的。
此外,我们将empty()
作为最终方法,因此MyStr
或MyBytes的子类"希望进一步提供特定行为"不会改变被认为是"的内容;"空";(因为只有一个东西可以被认为是空的(。
以上所有内容都将在mypy --strict
下进行类型检查。
在调用方,它们永远不会实例化MyObject[str]
或MyObject[bytes]
(事实上,mypy
会阻止这种情况,正如我们所希望的那样,因为MyObject
没有empty()
的实现(。相反,因为您在评论中说调用者将提前知道他们想要bytes
还是str
,所以他们直接实例化MyStr
或MyBytes
。