在抽象基类的具体子类之间强制执行类型安全

问题描述 投票:0回答:1

我的 Python 项目中面临类型安全问题,涉及抽象基类 (

AbstractClass
) 及其具体子类(
ConcreteClassA
ConcreteClassB
)。每个具体类都实现
AbstractClass
中的抽象方法,但我正在努力加强两个具体类之间的类型安全。

这是我的代码结构的简化版本:

class AbstractClass(ABC):
    class rational:
        pass

    @dataclass
    class Frac(rational):
        value1: int
        value2: int

    @dataclass
    class Whole(rational):
        value: int

    @classmethod
    @abstractmethod
    def foo(cls, x: int, y: int) -> rational:
        pass

    @classmethod
    @abstractmethod
    def boo(cls, r: rational) -> str:
        pass


class ConcreteClassA(AbstractClass):
    @classmethod
    def foo(cls, x: int, y: int) -> AbstractClass.rational:
        ...

    @classmethod
    def boo(cls, r: AbstractClass.rational) -> str:
        ...

    @staticmethod
    def __reduce(r: AbstractClass.rational) -> AbstractClass.Whole | AbstractClass.Frac:
        match r:
            case Rational1.Whole(_):
                return r
            case Rational1.Frac(x, y):
                if x == 0:
                    return AbstractClass.Whole(0)
                else:
                    d = Rational1.foo(abs(x), y)
                    if d == y:
                        return AbstractClass.Whole(x // d)
                    else:
                        return AbstractClass.Frac(x // d, y // d)
            case _:
                raise Exception("ERRR")


class ConcreteClassB(AbstractClass):
    @classmethod
    def foo(cls, x: int, y: int) -> AbstractClass.rational:
        ...

    @classmethod
    def boo(cls, r: AbstractClass.rational) -> str:
        ...

    @staticmethod
    def __reduce(r: AbstractClass.rational) -> AbstractClass.Whole | AbstractClass.Frac:
        match r:
            case Rational1.Whole(_):
                return r
            case Rational1.Frac(x, y):
                if x == 0:
                    return AbstractClass.Whole(0)
                else:
                    d = Rational1.foo(abs(x), y)
                    if d == y:
                        return AbstractClass.Whole(x // d)
                    else:
                        return AbstractClass.Frac(x // d, y // d)
            case _:
                raise Exception("ERRR")


a = ConcreteClassA.boo(ConcreteClassB.foo(9, -6))
b = ConcreteClassB.boo(ConcreteClassA.foo(9, -6))

编辑:正如您所看到的,有静态方法和其他相互调用的方法,并且我认为实现不会允许 Self 出现在抽象类中。

尽管有这种结构,但在

ConcreteClassA
ConcreteClassB
之间没有执行类型安全。例如,像
ConcreteClassA.boo
这样带有
ConcreteClassB.foo
参数的调用不会导致任何错误,这是不希望的。

我正在使用 Pyright 进行类型检查。如何修改代码以确保在

ConcreteClassA
ConcreteClassB
之间传递数据时产生错误?请注意,我不喜欢将泛型、类型别名或其他构造直接添加到主类中。

还有

@dataclass
内部的实现
AbstractClass
,就跟着它吧。

python inheritance subclass python-typing
1个回答
0
投票

我相信您正在寻找

Self
Self
用于表示当前类的实例 - 见下文:

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Self


class AbstractClass(ABC):
    class rational:
        pass

    @dataclass
    class Frac(rational):
        value1: int
        value2: int

    @dataclass
    class Whole(rational):
        value: int

    @classmethod
    @abstractmethod
    def foo(cls, x: int, y: int) -> Self:
        pass

    @classmethod
    @abstractmethod
    def boo(cls, r: Self) -> str:
        pass


class ConcreteClassA(AbstractClass):
    @classmethod
    def foo(cls, x: int, y: int) -> Self:
        ...

    @classmethod
    def boo(cls, r: Self) -> str:
        ...


class ConcreteClassB(AbstractClass):
    @classmethod
    def foo(cls, x: int, y: int) -> Self:
        ...

    @classmethod
    def boo(cls, r: Self) -> str:
        ...
    

a = ConcreteClassA.boo(ConcreteClassB.foo(9, -6)) # error
b = ConcreteClassB.boo(ConcreteClassA.foo(9, -6)) # error
a = ConcreteClassA.boo(ConcreteClassA.foo(9, -6)) # no error
b = ConcreteClassB.boo(ConcreteClassB.foo(9, -6)) # no error
© www.soinside.com 2019 - 2024. All rights reserved.