python - 为在 mixins 中返回 self 的方法注释返回类型
问题描述
我正在使用构建器模式,其中(大)类上的大多数方法都返回它们的标识(self
),因此被注释为返回它们所属的类的类型:
class TextBuilder:
parts: List[str] # omitted
render: Callable[[], str] # for brevity
def text(self, val: str) -> "TextBuilder":
self.parts.append(val)
return self
def bold(self, val: str) -> "TextBuilder":
self.parts.append(f"<b>{val}</b>")
return self
...
示例用法:
joined_text = TextBuilder().text("a ").bold("bold").text(" text").render()
# a <b>bold</b> text
现在,随着这个类越来越大,我想将相关方法拆分并分组到 mixins 中:
class BaseBuilder:
parts: List[str] # omitted
render: Callable[[], str] # for brevity
class TextBuilder(BaseBuilder):
def text(self, val: str):
self.parts.append(val)
return self
...
class HtmlBuilder(BaseBuilder):
def bold(self, val: str):
self.parts.append(f"<b>{val}</b>")
return self
...
class FinalBuilder(TextBuilder, HtmlBuilder):
pass
但是,我没有看到一种方法来正确注释 mixin 类的返回类型,以使生成的类FinalBuilder
总是让 mypy 相信它返回FinalBuilder
而不是 mixin 类之一。当然,所有这些都假设我想要实际注释self
和返回类型,因为它们可能无法从这些方法内部发生的事情中推断出来。
我尝试使 mixin 类成为通用类并将它们显式标记为返回T
绑定到的类型BaseBuilder
,但这并不满足 mypy. 有任何想法吗?现在我将跳过所有这些恶作剧并在任何地方省略返回类型,因为它们应该在使用时正确推断FinalBuilder
,但我仍然很好奇是否有一种通用的方法来解决这个问题。
解决方案
如果您希望返回类型始终self
不变,只需像这样注释self
参数:
from typing import List, Callable, TypeVar
T = TypeVar('T', bound=BaseBuilder)
class BaseBuilder:
parts: List[str] # omitted
render: Callable[[], str] # for brevity
class TextBuilder(BaseBuilder):
def text(self: T, val: str) -> T:
self.parts.append(val)
return self
...
class HtmlBuilder(BaseBuilder):
def bold(self: T, val: str) -> T:
self.parts.append(f"<b>{val}</b>")
return self
...
class FinalBuilder(TextBuilder, HtmlBuilder):
pass
# Type checks
f = FinalBuilder().text("foo").bold("bar")
# Mypy states this is type 'FinalBuilder'
reveal_type(f)
几点注意事项:
如果我们不注释
self
,mypy 通常会假设它是我们当前包含的任何类的类型。但是,如果你愿意,可以给它一个自定义类型提示,只要该类型提示与班级。(例如,将 a 添加def foo(self: int) -> None
到 HtmlBuilder 是不合法的,因为 int 不是 HtmlBuilder 的超类型。)我们通过使用泛型来利用这一点,
self
因此我们可以指定更具体的返回类型。有关更多详细信息,请参阅 mypy 文档:https ://mypy.readthedocs.io/en/stable/generics.html#generic-methods-and-generic-self
我将 TypeVar 限制为
BaseBuilder
这样两个函数都可以看到parts
andrender
字段。如果您希望您的text(...)
和bold(...)
函数也分别看到在 TextBuilder 和 HtmlBuilder 中定义的字段,您需要创建两个绑定到这些更具体的子类的 TypeVar。
推荐阅读
- python - auto_increment 主键和链接表(Mysql)
- r - 分离单元格内的数据并复制行数据
- google-sheets - 将 Google 协作平台数据提取到 Google 表格中
- amazon-web-services - aws signature get api 中出现缺少参数和 400 错误
- mailgun - Mailgun 的发送 IP 198.61.254.54 目前在 SORBS 上列出。支持人员没有回复我的票。我该怎么办?
- python - 在Python中水平从pdf中提取文本
- schema - Jooq 模式名称作为查询参数
- html - 单选按钮填充
- android - Visual Studio 在 Android 应用中找不到扩展方法 Splat.BitmapMixins.FromNative() 和 Splat.BitmapMixins.ToNative()
- c++ - P1008(“禁止与用户声明的构造函数聚合”)在实践中何时有用?