Python 在mixin中为返回self的方法注释返回类型

Python 在mixin中为返回self的方法注释返回类型,python,types,annotations,pycharm,mypy,Python,Types,Annotations,Pycharm,Mypy,我使用的是一种构建器模式,其中大类上的大多数方法都返回自己的标识,并因此被注释以返回它们所属的类的类型: 类TextBuilder: 零件:省略列表[str] render:为简洁起见,可调用[],str] def textself,val:str->TextBuilder: 附肢 回归自我 def boldself,val:str->TextBuilder: self.parts.appendf{val} 回归自我 ... 用法示例: joined_text=TextBuilder.texta

我使用的是一种构建器模式,其中大类上的大多数方法都返回自己的标识,并因此被注释以返回它们所属的类的类型:

类TextBuilder: 零件:省略列表[str] render:为简洁起见,可调用[],str] def textself,val:str->TextBuilder: 附肢 回归自我 def boldself,val:str->TextBuilder: self.parts.appendf{val} 回归自我 ... 用法示例:

joined_text=TextBuilder.texta.boldbold.text.render 黑体字 现在,随着这个类越来越大,我想将相关的方法拆分并分组为mixin:

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和return类型,因为它们可能无法从这些方法内部的情况推断出来


我曾尝试将mixin类设置为泛型,并将它们显式标记为返回绑定到BaseBuilder的类型T,但这并不能满足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通常会假定它是当前包含在其中的任何类的类型。但是,如果需要,可以给它一个自定义类型提示,只要该类型提示与类兼容。例如,将def fooself:int->None添加到HtmlBuilder是不合法的,因为int不是HtmlBuilder的超类型

我们通过使self泛型来利用这一点,以便可以指定更具体的返回类型

有关更多详细信息,请参阅mypy文档:

我将TypeVar绑定到BaseBuilder,以便两个函数都能够看到零件和渲染字段。如果你想要你的文字。。。大胆的。。。函数要分别查看TextBuilder和HtmlBuilder中定义的字段,需要创建两个绑定到这些更具体的子类的TypeVar