在父 class 中键入 subclass
Type subclass from inside the parent class
假设我们有以下 class:
from __future__ import annotations
class BaseSwallow:
# Can't get the ref to `BaseSwallow` at runtime
DerivedSwallow = NewType('DerivedSwallow', BaseSwallow)
def carry_with(self, swallow: DerivedSwallow):
self.carry()
swallow.carry()
def carry(self):
pass
class AfricanSwallow(BaseSwallow): pass
godOfSwallows = BaseSwallow()
africanSwallow = AfricanSwallow()
africanSwallow.carry_with(godOfSwallows) # Should fail at static typing
我想强制要求 carry_with
只能用 classes 派生自 BaseSwallow
的实例调用,所以我使用 NewType
来做到这一点 like the doc says。
但是,NewType
需要引用基础 class 对象才能工作,而我在运行时无权访问它。在运行前,由于 annotations
模块,我有 "access" 到 BaseSwallow
但当 运行.
时它仍然会失败
我知道在大多数情况下,为 BaseSwallow
使用抽象基础 Class 是最好的做法,但我不能那样做 for various reasons。
有什么想法吗?
您可以将 carry
标记为 abstractmethod
吗?例如,像这样的东西:
import abc
class BaseSwallow:
def carry_with(self, swallow: BaseSwallow) -> None:
self.carry()
swallow.carry()
@abc.abstractmethod
def carry(self) -> None:
raise NotImplementedError('implementation of carry needed')
derived classes 然后可以实现该方法,但是因为基础 class 没有尝试实例化它会导致类型检查失败,表明 BaseSwallow
是一个抽象class 由于缺少属性 carry
我不认为有一种方法可以使用类型注释来表达“T
的所有子 classes,不包括 T
”。如果你有一组固定的 subclasses,你可以使用 Union
类型来捕获它们,但这可能不是你想要的。我认为 是您最好的选择:只需使用 BaseSwallow
基础 class 而不是制作复杂的类型来排除基础 class 本身。
此外,我认为您误解了 NewType
的用法。 NewType
用于创建需要显式转换的类型的别名。例如:
URL = NewType('URL', str)
def download(url: URL): ...
link_str = "https://..." # inferred type is `str`
link_url = URL(link_str) # inferred type is `URL`
download(link_str) # type error
download(link_url) # correct
编辑: 如果您不介意一点开销,您可以通过额外的继承级别来实现。创建 BaseSwallow
的子类型(为方便起见命名为 Swallow
),并让所有派生的 class 继承 Swallow
而不是 BaseSwallow
。这样,您可以使用 Swallow
类型注释 carry_with
方法:
class BaseSwallow:
def carry_with(self, swallow: 'Swallow'): # string as forward reference
self.carry()
swallow.carry()
def carry(self):
pass
class Swallow(BaseSwallow): pass # dummy class to serve as base
class AfricanSwallow(Swallow): pass
godOfSwallows = BaseSwallow()
africanSwallow = AfricanSwallow()
africanSwallow.carry_with(godOfSwallows) # mypy warns about incompatible types
假设我们有以下 class:
from __future__ import annotations
class BaseSwallow:
# Can't get the ref to `BaseSwallow` at runtime
DerivedSwallow = NewType('DerivedSwallow', BaseSwallow)
def carry_with(self, swallow: DerivedSwallow):
self.carry()
swallow.carry()
def carry(self):
pass
class AfricanSwallow(BaseSwallow): pass
godOfSwallows = BaseSwallow()
africanSwallow = AfricanSwallow()
africanSwallow.carry_with(godOfSwallows) # Should fail at static typing
我想强制要求 carry_with
只能用 classes 派生自 BaseSwallow
的实例调用,所以我使用 NewType
来做到这一点 like the doc says。
但是,NewType
需要引用基础 class 对象才能工作,而我在运行时无权访问它。在运行前,由于 annotations
模块,我有 "access" 到 BaseSwallow
但当 运行.
我知道在大多数情况下,为 BaseSwallow
使用抽象基础 Class 是最好的做法,但我不能那样做 for various reasons。
有什么想法吗?
您可以将 carry
标记为 abstractmethod
吗?例如,像这样的东西:
import abc
class BaseSwallow:
def carry_with(self, swallow: BaseSwallow) -> None:
self.carry()
swallow.carry()
@abc.abstractmethod
def carry(self) -> None:
raise NotImplementedError('implementation of carry needed')
derived classes 然后可以实现该方法,但是因为基础 class 没有尝试实例化它会导致类型检查失败,表明 BaseSwallow
是一个抽象class 由于缺少属性 carry
我不认为有一种方法可以使用类型注释来表达“T
的所有子 classes,不包括 T
”。如果你有一组固定的 subclasses,你可以使用 Union
类型来捕获它们,但这可能不是你想要的。我认为 BaseSwallow
基础 class 而不是制作复杂的类型来排除基础 class 本身。
此外,我认为您误解了 NewType
的用法。 NewType
用于创建需要显式转换的类型的别名。例如:
URL = NewType('URL', str)
def download(url: URL): ...
link_str = "https://..." # inferred type is `str`
link_url = URL(link_str) # inferred type is `URL`
download(link_str) # type error
download(link_url) # correct
编辑: 如果您不介意一点开销,您可以通过额外的继承级别来实现。创建 BaseSwallow
的子类型(为方便起见命名为 Swallow
),并让所有派生的 class 继承 Swallow
而不是 BaseSwallow
。这样,您可以使用 Swallow
类型注释 carry_with
方法:
class BaseSwallow:
def carry_with(self, swallow: 'Swallow'): # string as forward reference
self.carry()
swallow.carry()
def carry(self):
pass
class Swallow(BaseSwallow): pass # dummy class to serve as base
class AfricanSwallow(Swallow): pass
godOfSwallows = BaseSwallow()
africanSwallow = AfricanSwallow()
africanSwallow.carry_with(godOfSwallows) # mypy warns about incompatible types