首页 > 编程问答 >为 mixins 中返回 self 的方法注释返回类型

为 mixins 中返回 self 的方法注释返回类型

时间:2024-07-23 16:13:58浏览次数:12  
标签:python pycharm python-typing mypy

我正在使用构建器模式,其中(大)类上的大多数方法返回其标识( 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

现在,随着这个类变得越来越大,我想将相关方法拆分并分组到混合中:

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

但是,我没有找到一种方法来正确注释混合类的返回类型,从而生成结果类 FinalBuilder 总是让 mypy 相信它返回 FinalBuilder 而不是 mixin 类之一。当然,假设我想 实际上 注释 self 并返回类型,因为它们可能无法从这些方法内部发生的情况推断出来。

我尝试使 mixin 类通用并标记它们明确返回一个绑定到 T 的类型 BaseBuilder ,但这并不能满足mypy.有任何想法吗?现在我将跳过所有这些恶作剧并省略各处的返回类型,因为在使用 FinalBuilder 时应该正确推断它们,但我仍然很好奇是否有通用的方法来解决这个问题。


你遇到的问题是,在 Python 中,你不能对返回类型使用像“mixin 类本身的类型”这样的东西。 当你在 mixin 中定义一个方法时,你不知道它最终会被合并到哪个类中。

不过,有一些方法可以解决这个问题,让你在一定程度上实现类型安全:

1. 使用 TypeVar 和泛型函数:

from typing import List, Callable, TypeVar, Generic

T = TypeVar('T', bound='BaseBuilder')

class BaseBuilder:
    parts: List[str]
    render: Callable[[], str]

class TextBuilder(BaseBuilder, Generic[T]):
    def text(self: T, val: str) -> T:
        self.parts.append(val)
        return self

class HtmlBuilder(BaseBuilder, Generic[T]):
    def bold(self: T, val: str) -> T:
        self.parts.append(f"<b>{val}</b>")
        return self

class FinalBuilder(TextBuilder[FinalBuilder], HtmlBuilder[FinalBuilder]):
    pass

joined_text = FinalBuilder().text("a ").bold("bold").text(" text").render()

在这个例子中,我们使用了 TypeVar 来定义一个名为 T 的类型变量,它被限制为 BaseBuilder 的子类。然后,我们在 mixin 类中使用 Generic[T] 来表明它们是泛型类,并使用 self: T 来指定方法返回的类型是 T 。 最后,在 FinalBuilder 中,我们明确地将 T 指定为 FinalBuilder ,这样 mypy 就知道 text bold 方法会返回 FinalBuilder 实例。

2. 使用 @overload 装饰器 (Python 3.11+):

从 Python 3.11 开始,你可以使用 @overload 装饰器来为不同的返回类型提供多个类型提示:

from typing import List, Callable, overload

class BaseBuilder:
    parts: List[str]
    render: Callable[[], str]

class TextBuilder(BaseBuilder):
    @overload
    def text(self: 'TextBuilder', val: str) -> 'TextBuilder': ...
    @overload
    def text(self, val: str) -> 'FinalBuilder': ...
    def text(self, val: str):
        self.parts.append(val)
        return self

# ... 为 HtmlBuilder.bold 添加类似的 @overload ...

class FinalBuilder(TextBuilder, HtmlBuilder):
    pass

这种方法更明确地说明了方法可以返回的不同类型,但也更加冗长,特别是当你有很多 mixin 和方法时。

选择哪种方法取决于你的个人喜好和 Python 版本。 两种方法都能帮助你在使用 mixin 时提高类型安全性。

标签:python,pycharm,python-typing,mypy
From: 62029791

相关文章

  • Python - 检查签名注释是否属于特定类
    使用forsigininspect.signature.parameters.items():ifisinstance(sig[1].annotation,inspect._empty):print("empty")时,我从来没有让控制台说打印“空”。即使在if子句之前使用print(sig[1].annotation)时给出的输出是:<class'inspect._e......
  • 从代码调用 alembic 命令后,Python 记录器不再记录
    我在代码中使用alembic在应用程序启动时应用数据库迁移。我还使用Python的内置logginglib来登录终端。应用迁移后(或运行任何打印到alembic的命令),我的记录器停止工作。stdout代码:预期输出:importloggingimportalembic.commandfr......
  • python 使用 random模块生成随机测试数据
    前言python中可以使用random模块生成随机测试数据常用函数说明random.seed(a)设置初始化随机种子,可输出相同随机数序列;a取整数或浮点数,不设置时默认以系统时间为种子random.random()生成一个0.0到1.0之间的随机浮点数random.uniform(a,b)生成一个[a,b]之间......
  • 如何在包级别禁用 mypy 错误代码?
    variable=[]错误:error:Needtypeannotationfor'variable'(hint:"variable:List[<type>]=...")在配置文件中:mypy.inidisallow_any_expr=False是否有任何方法可以通过配置文件中的标志覆盖此错误?无法在配置文件的mypy中禁用“需......
  • Python 上债券的内部收益率
    在Excel中,有一个公式(IRR.Payment:https://support.microsoft.com/fr-fr/office/fonction-tri-paiements-de1242ec-6477-445b-b11b-a303ad9adc9d)计算债券的IRR。我正在尝试在python算法上重现这一点,以便能够在我的代码中计算它。我在网上找到了这段代码:importnumpy......
  • 使用Python连接ftps服务器时nlst返回错误
    我可以使用TotalCommander登录服务器:ftps://publishedprices.co.il用户名:“奥舍拉德”密码为空并带有lftp-uosherad:publishedprices.co.il但是当我尝试登录并使用Python获取文件列表时nlst函数返回超时代码:fromftplibimportFTP_TLS......
  • 在我的 python 代码中,我无法使用 slixmpp 连接到 Openfire 服务器
    在我的python代码中,我无法连接到Openfire服务器。我想连接到OpenFire服务器我的代码是importthreadingimporttkinterastkfromtkinterimportsimpledialog,scrolledtextimportjsonimportloggingimportasynciofromslixmppimportClientXMPPcla......
  • 如何在Python中获取字符的unicode?
    想要获取中文或越南语的汉名和日文字符的unicode我已经尝试过这些代码text="......
  • 三种语言实现计算逆序对的数量(C++/Python/Java)
    题目给定一个长度为......
  • python项目中__init__.py是什么文件有什么作用
    __init__.py 文件在Python项目中的作用主要是将目录标识为一个Python包。它在包的初始化过程中起到了重要作用。具体来说,__init__.py 文件有以下几个功能:1.标识包:-当一个目录中包含 __init__.py 文件时,这个目录就被视为一个Python包。这样,Python解释器就能够识别......