【问题标题】:How to avoid duplicating arguments definition when inheriting from abstract class?从抽象类继承时如何避免重复参数定义?
【发布时间】:2021-09-04 18:36:33
【问题描述】:

我有一个用 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 尖叫代码重复。而且,老实说,我同意他的观点。

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

【问题讨论】:

  • 从长远来看,手动执行此操作会更好。否则,请使用*args, **kwargs
  • 为什么从长远来看会更好?如果我必须更改某些参数的类型提示怎么办?那我必须重构所有继承的类吗?当它们位于从抽象类继承的抽象方法中时,pylint 也会对 *args 和 **kwargs 尖叫。
  • 你不能改变类型提示而不违反里氏替换原则。 签名是ABC规定的重要内容。
  • 仅仅因为 ABC 不能强制保留签名并不意味着您可以随意更改它。
  • 但我不想更改类型提示。我只是觉得每次继承 ABC 时都盲目地重复它们是多余的。

标签: python types code-duplication abstract-base-class


【解决方案1】:

这里的一个解决方案是在抽象类和子类中都使用单个 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-02
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多