主要 class 输入 Python mixins

Main class typing in Python mixins

我有一个 class 拆分成混合:

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

mixin 看起来像这样:

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

现在我想在 class 和 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也会继承这个class,mixins会把它当作argument/return类型使用,但是这个无论如何都会导致错误的类型。可以修复吗??

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

在使用 mixin 继承的情况下,protocols and structural subtyping and TYPE_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

我发现了如何在没有协议或其他不必要的代码的情况下完成这个技巧,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: The erased type of self "Type[... MyObject]" is not a supertype of its class "Type[...MyObjectFilesMixin]"

但是要让 IDE 和 MyPy 正确查看和理解这些方法和类型需要付出一点代价!