首页 > 编程问答 >如何正确地将类型提示添加到复杂的 Mixin 类中?

如何正确地将类型提示添加到复杂的 Mixin 类中?

时间:2024-07-23 11:56:10浏览次数:9  
标签:python python-typing mypy mixins

向 mixin 类添加类型注释以使代码通过 mypy 检查的正确方法是什么:

example1.py:

class HostClass:
    def host_method(self) -> None:
        pass

    def overridden_host_method(self) -> None:
        pass

class MixinClass:
    def mixin_method(self) -> None:
        self._other_mixin_method()
        self.host_method()

    def _other_mixin_method(self) -> None:
        pass

    def overridden_host_method(self) -> None:
        super().overridden_host_method()


class MyClass(MixinClass, HostClass):
    pass


obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
% mypy example1.py
example1.py:11: error: "MixinClass" has no attribute "host_method"  [attr-defined]
example1.py:17: error: "overridden_host_method" undefined in superclass  [misc]
Found 2 errors in 1 file (checked 1 source file)

mypy 文档中推荐的解决方案 ( https:/ /mypy.readthedocs.io/en/latest/more_types.html#mixin-classes ) 以及对 如何正确向 Mixin 类添加类型提示? 的答案中不起作用。| ||example2.py(HostProtocol 作为“self”的类型注释):

example3.py(HostProtocol 作为 MixinClass 的基类):

from typing import Protocol


class HostProtocol(Protocol):
    def host_method(self) -> None:
        ...

    def overridden_host_method(self) -> None:
        ...


class HostClass:
    def host_method(self) -> None:
        pass

    def overridden_host_method(self) -> None:
        pass


class MixinClass:
    def mixin_method(self: HostProtocol) -> None:
        self._other_mixin_method()
        self.host_method()

    def _other_mixin_method(self) -> None:
        pass

    def overridden_host_method(self) -> None:
        super().overridden_host_method()


class MyClass(MixinClass, HostClass):
    pass


obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
% mypy example2.py
example2.py:22: error: "HostProtocol" has no attribute "_other_mixin_method"  [attr-defined]
example2.py:29: error: "overridden_host_method" undefined in superclass  [misc]
Found 2 errors in 1 file (checked 1 source file)

example4.py(切换 MyClass 基类的顺序):| ||但是 overridden_​​host_method() 不再被重写:

from typing import Protocol

class HostProtocol(Protocol):
    def host_method(self) -> None:
        ...
 
    def overridden_host_method(self) -> None:
        ...


class HostClass:
    def host_method(self) -> None:
        pass

    def overridden_host_method(self) -> None:
        pass

class MixinClass(HostProtocol):
    def mixin_method(self) -> None:
        self._other_mixin_method()
        self.host_method()

    def _other_mixin_method(self) -> None:
        pass

    def overridden_host_method(self) -> None:
        super().overridden_host_method()


class MyClass(MixinClass, HostClass):
    pass


obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
% mypy example3.py
example3.py:34: error: Cannot instantiate abstract class "MyClass" with abstract attribute "host_method"  [abstract]
example3.py:34: note: "host_method" is implicitly abstract because it has an empty function body. If it is not meant to be abstract, explicitly `return` or `return None`.
Found 1 error in 1 file (checked 1 source file)

i。 e.不打印“Mixin overrides”。

from typing import Protocol

class HostProtocol(Protocol):
    def host_method(self) -> None:
        ...
 
    def overridden_host_method(self) -> None:
        ...


class HostClass:
    def host_method(self) -> None:
        pass

    def overridden_host_method(self) -> None:
        pass

class MixinClass(HostProtocol):
    def mixin_method(self) -> None:
        self._other_mixin_method()
        self.host_method()

    def _other_mixin_method(self) -> None:
        pass

    def overridden_host_method(self) -> None:
        print("Mixin overrides")
        super().overridden_host_method()


class MyClass(HostClass, MixinClass):
    pass


obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()
mypy example4.py
Success: no issues found in 1 source file

MixinClass 应:

% python example4.py
% 

从 HostClass 调用方法

也从自身调用方法

  • 覆盖 HostClass 的方法
  • call also a method from itself
  • override a method of the HostClass

你遇到的问题是,mixin 期望存在于它扩展的类中的一些属性或方法,但在 mixin 本身被定义时,这些属性或方法是不可用的。你有几种方法可以解决这个问题。

1. 使用协议和类型注释

这是 mypy 文档推荐的方法,并且在你的情况下也能工作。 你在 example2.py example3.py 中几乎做对了,但你需要组合这两种方法。

from typing import Protocol

class HostProtocol(Protocol):
    def host_method(self) -> None:
        ...

    def overridden_host_method(self) -> None:
        ...

class HostClass:
    def host_method(self) -> None:
        print("HostClass.host_method()")

    def overridden_host_method(self) -> None:
        print("HostClass.overridden_host_method()")

class MixinClass(HostProtocol):
    def mixin_method(self) -> None:
        self._other_mixin_method()
        self.host_method()

    def _other_mixin_method(self) -> None:
        print("MixinClass._other_mixin_method()")

    def overridden_host_method(self) -> None:
        print("MixinClass.overridden_host_method()")
        super().overridden_host_method()

class MyClass(HostClass, MixinClass):
    pass

obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()

在这个例子中,我们定义了一个 HostProtocol 协议,它描述了 MixinClass 所期望的方法。然后,我们让 MixinClass 继承 HostProtocol 。这告诉 mypy, MixinClass 可以在任何实现了 HostProtocol 的类中使用。

2. 使用 @runtime_checkable 装饰器

你可以使用 typing.runtime_checkable 装饰器将协议标记为可在运行时检查。这允许你在运行时检查对象是否符合协议,即使它没有在类型提示中声明。

from typing import Protocol, runtime_checkable

@runtime_checkable
class HostProtocol(Protocol):
    def host_method(self) -> None:
        ...

    def overridden_host_method(self) -> None:
        ...

# ... rest of the code is the same as in the previous example

这种方法的优点是,你不需要改变 HostClass 的定义,即使它没有明确继承 HostProtocol ,mypy 也会识别它。

3. 明确地将 mixin 应用到类

如果你不想使用协议,你可以明确地将 mixin 应用到类。 这意味着将 mixin 类作为参数传递给类定义,并在类定义中调用 mixin 类的方法。

class HostClass:
    def host_method(self) -> None:
        print("HostClass.host_method()")

    def overridden_host_method(self) -> None:
        print("HostClass.overridden_host_method()")

class MixinClass:
    def mixin_method(self) -> None:
        self._other_mixin_method()
        self.host_method()

    def _other_mixin_method(self) -> None:
        print("MixinClass._other_mixin_method()")

    def overridden_host_method(self) -> None:
        print("MixinClass.overridden_host_method()")
        super().overridden_host_method()

class MyClass(HostClass):
    def __init__(self) -> None:
        super().__init__()
        MixinClass().mixin_method(self)
        MixinClass().overridden_host_method(self)

obj = MyClass()
obj.mixin_method()
obj.overridden_host_method()

这种方法的优点是不需要使用协议,但是它需要更改你的类的定义,并且可能比使用协议更复杂。

选择哪种方法取决于你的具体需求和编码风格。 如果你想要最灵活和可扩展的解决方案,那么使用协议是最好的方法。 如果你想要一个更简单的解决方案,并且你不介意更改类的定义,那么明确地将 mixin 应用到类可能更适合你。

标签:python,python-typing,mypy,mixins
From: 77283935

相关文章

  • Python字段的字符串注释
    Python是否支持类字段的任何类型的字符串注释?例如,在Golang中,我可以定义这样的结构,带有可选的字符串标签:typeUserstruct{Namestring`example:"name"`}我需要在Python中定义一个新类,其中包含包含点.的字段名称。我希望可能有某种方法来注释字段,或者......
  • 具有未定义变量和注释的有效 Python 行
    我来了一篇文章,其中包含未定义的变量名称和某些类型注释。该行有效。它有什么作用以及可能的用途是什么?withundefinedvariablenamewithsometypeannotation.Thelineisvalid.Whatitdoesandwhatarepossibleusages?>>>x:int>>>xTraceback(mostr......
  • 使用 Python 通过逻辑应用运行长时间运行的 Azure Functions
    我已经尝试解决这个问题有一段时间了,但我似乎找不到解决方案。因此,正如标题所示,我试图通过函数在逻辑应用程序中运行长时间运行的操作。我有一个python代码,可以比较2个excel文件并进行一些转换。它工作正常,但是,Excel文件包含近20k行(它是动态的,将来会添加更多行),因此......
  • 使用递归函数计算阶乘时,我在 python 中遇到类型错误
    defcalc_fact(n):如果(n==1或n==0):返回1别的:n*calc_fact(n-1)print(calc_fact(5))试图创建函数来计算阶乘,不支持类型错误操作数*:对于int或Nonetype我不知道为什么谢谢Python代码中出现“类型错误:不支持的操作数类型为*:'int'和'NoneType'”表明你......
  • 如何调试 python Flask [84] [CRITICAL] WORKER TIMEOUT?
    调试:gtts.tts:保存到temp.mp37月22日09:10:56PM[2024-07-2215:40:56+0000][84][严重]工作超时(pid:87)|||7月22日09:10:56PM[2024-07-2215:40:56+0000][87][INFO]工人退出(pid:87)7月22日09:10:57PM[2024-07-2215:40:57+0000][95][INF......
  • 类型错误:无法将函数返回值转换为 Python 类型!签名是 () -> 处理 anaconda spider
    这是代码:importosimportrandomimportnumpyasnpimportpandasaspdimporttensorflowastffromtensorflow.kerasimportbackendasKfromtensorflow.keras.layersimportDense,Dropout,Flatten,Conv2D,MaxPool2D,Input......
  • python进阶---闭包与装饰器
    一、闭包        在Python中,闭包是指一个函数内部定义的函数,这个内部函数可以访问并修改其外部函数的局部变量,即使外部函数已经执行完毕。闭包可以通过多层函数嵌套来实现。    闭包的三要素:    1、外部函数嵌套内部函数    2、外部函数返......
  • 强制从当前包自动导入的 Python 以此包的名称为前缀
    我在VSCode中使用Python和Pylance扩展。在我正在编辑的自己的包中,自动添加的导入(设置“导入格式:绝对”)如下所示:frommydirectory.myfileimportmyclass但是,我的Python包正在被被一个(非常愚蠢且不可协商的)外部系统消耗,该系统拒绝正确解释它,除非导入的格式特别......
  • Python语言-面向对象
    知识代码classJobSalary(object):job=''def__init__(self,city):self.jobname="数据分析师"self.exp=''self.city=city#方法defdata_normalize(self,data):print(f'正在规范化......
  • 需要帮助使用 Selenium Python 单击 Microsoft Teams 按钮
    我将Python与Selenium结合使用,并自动登录MicrosoftTeams。进入后,弹出窗口显示我需要单击“立即切换”以切换到V2版本。我似乎无法使用SeleniumPython成功单击此按钮。谁能帮我自动点击这个按钮?这是我不成功的尝试:self.driver.find_element(By.CLASS_NAME,......