【问题标题】:Main class typing in Python mixinsPython mixins 中的主类类型
【发布时间】:2020-12-15 07:58:20
【问题描述】:

我有一个类拆分成 mixins:

class MyObject(MyObjectFilesMixin, MyObjectProcessingMixin, ...):
    def __init__(self, value):
        self.value = self.preprocess(value)

mixin 看起来像这样:

class MyObjectFilesMixin:
    def load_from_file(cls, filename):
        return ...

现在我想在类和 mixins 中添加类型:

class MyObjectFilesMixin:
    def load_from_file(cls, filename: str) -> MyObject:
        return ...


class MyObjectProcessingMixin:
    def preprocess(self: MyObject, value: bytes):
        return value  # logic is omitted

    def append(self: MyObject, other: MyObject):
        self.value += other.value

但它会导致循环链接。当然我可以创建一些MyObjectBase(遵循依赖倒置原则),这样MyObject也会继承这个类,mixins会使用它作为参数/返回类型,但这无论如何都会导致错误的类型。可以修复吗??

我错过了很多来自 C++ 的头文件和源文件

【问题讨论】:

    标签: python include mixins type-hinting python-typing


    【解决方案1】:

    在使用 mixin 继承的情况下,protocols and structural subtypingTYPE_CHECKING 可以通过避免循环导入来帮助成功键入类,它可能如下所示:

    # my_object.py
    from mixins import ProcessingMixin
    
    
    class MyObject(ProcessingMixin):
        def __init__(self, value):
            self.value = self.preprocess(value)
    
        def some_process(self, value) -> bytes:
            ...
    
    # mixins.py
    from typing import Protocol, TYPE_CHECKING
    
    if TYPE_CHECKING:
        from my_object import MyObject
    
    class ValueObjectProto(Protocol):
        """Protocol for value processing methods."""
        value: bytes
    
        def preprocess(self, value: bytes) -> bytes: ...
        def some_process(self, value) -> bytes: ...
    
    
    class MyObjectFilesMixin:
        def load_from_file(cls, filename: str) -> MyObject:
            return cast(Type[MyObject], cls)(1)
    
    class ProcessingMixin:
        def preprocess(self: ValueObjectProto, value: bytes) -> bytes:
            value = self.some_process(value)
            return value
    
        def append(self: ValueObjectProto, other: ValueObjectProto) -> None:
            self.value += other.value
    

    【讨论】:

    • 它类似于我对MyObjectBase 类的想法,只是更“神奇”的用法,但它也是 1. 需要规范所有方法,我在许多文件中有几十个,2 . 行obj: MyObject = MyObject.load_from_file(...) 将是错误的,因为load_from_file 将返回一些协议对象,这导致我的对象类和这样的协议之间存在歧义......定义协议是构建框架以处理多个单独的类的一个很好的解决方案,但是在这里,有提到的缺点,它看起来像一个拐杖?
    • 并非如此,协议更灵活,允许您在所有情况下都不要使用继承。 mypy 的可能性有限,但希望有人能提出更优雅的解决方案。
    • 我找到了一个更简单的解决方案,看看?
    【解决方案2】:

    我发现了如何在没有协议或其他不必要代码的情况下完成这个技巧,DRY! 我的解决方案很简单:

    from typing import TYPE_CHECKING, Type
    if TYPE_CHECKING:
        from my_object import MyObject
    MO = Type('MyObject')
    
    
    class MyObjectFilesMixin:
        def load_from_file(cls: MO, filename: str) -> 'MyObject':
            # Now I'm able to access all the methods of MyObject by cls
            # with correct IDE support and MyPy checking
            return ...
    
    
    class MyObjectProcessingMixin:
        def preprocess(self: 'MyObject', value: bytes):
            return value  # logic is omitted
    
        def append(self: 'MyObject', other: 'MyObject'):
            self.value += other.value
    

    但是,我收到另一个警告,可能是因为 MyPy 不希望将子级用作父级中的类型:

    Mypy:自我擦除的类型“Type[... MyObject]”不是其类“Type[...MyObjectFilesMixin]”的超类型

    但是要让 IDE 和 MyPy 正确地看到和理解方法和类型需要一点成本!

    【讨论】:

      猜你喜欢
      • 2021-01-03
      • 1970-01-01
      • 2023-01-25
      • 2019-08-28
      • 1970-01-01
      • 2016-12-22
      • 2021-10-01
      • 2014-04-22
      • 2011-04-22
      相关资源
      最近更新 更多