首页 > 解决方案 > 从抽象类继承时如何避免重复参数定义?

问题描述

我有一个用 Python 编写的抽象类:

class AbsctracClass(ABC):

    @abstractmethod
    def method(self, 
        value1: int,
        value2: float,
        value3: str,
        value4: Optional[list] = None,
        value5: Optional[int] = None,
        value6: Optional[float] = None,
        ... etc ...,
        ):
        ''' An abstract method  for an abstract class '''

它有一个带有很多参数的抽象方法。我知道,我知道,将大量参数传递给函数不是一个好习惯,但现在这与我的问题无关。

现在我想编写另一个继承自 AbstractClass 的类。而且我必须手动复制所有参数及其来自抽象类的类型提示。

class AnotherClass(AbstractClass):

    def method(self, 
        value1: int,
        value2: float,
        value3: str,
        value4: Optional[list] = None,
        value5: Optional[int] = None,
        value6: Optional[float] = None,
        ... etc ...,
        ):
        return value3 * (value2 + value3)  

当我有几个抽象方法和几个类继承自它时,它不仅很麻烦,而且pylint对代码重复感到尖叫。而且,老实说,我同意他的看法。

显然必须有更好的方法。是吗?

标签: pythontypescode-duplicationabstract-base-class

解决方案


NamedTuple这里的一种解决方案可能是在抽象类和子类中使用单个参数。如果我们有这样的NamedTuple定义:

from typing import NamedTuple, Optional 

class ArgsTuple(NamedTuple):
    value1: int
    value2: float
    value3: str
    value4: Optional[list] = None
    value5: Optional[int] = None
    value6: Optional[float] = None

然后你可以像这样重构你的基类:

from abc import ABC, abstractmethod

# ArgsTuple as defined above

class AbstractClass(ABC):
    @abstractmethod
    def method(self, all_args: ArgsTuple):
        ''' An abstract method  for an abstract class '''

您的具体实现还必须更改它们的签名method,以保持基类和子类之间的签名相同。调用函数的方式也需要改变——method现在只接受一个参数,所以你必须在将所有参数ArgsTuple传递给method.

在实现方面method,您现在必须从ArgsTuple方法中解压缩参数。这样做的一种方法是这样的,一些静态类型检查器可能会遇到这种情况(MyPy 可以推断类型,但如果我没记错的话,如果你使用元组解包,PyCharm 会丢失):

# AbstractClass as refactored above
# ArgsTuple as defined above 

class AnotherClass(AbstractClass):
    def method(self, all_args: ArgsTuple):
        _, value2, value3, *other_args = all_args
        return value3 * (value2 + value3)

另一种方法是这样的,一些静态类型检查器可能会发现它更容易处理:

# AbstractClass as refactored above
# ArgsTuple as defined above 

class AnotherClass(AbstractClass):
    def method(self, all_args: ArgsTuple):
        value3 = all_args.value3
        return value3 * (all_args.value2 + value3)

推荐阅读