【问题标题】:How to override in multiple classes without code duplication (Python)如何在不重复代码的情况下覆盖多个类(Python)
【发布时间】:2021-09-11 14:23:44
【问题描述】:

我有一个父类 A 有几个继承自它的类 (B,C,...)。

我有一些函数is_class_AA 中实现,我想以同样的方式在BC 中覆盖它。

让我们说:

class A:
    def is_class_A():
        print("We are in class A")

class B(A):
    def is_class_A():
        print("Nope")

class C(A):
    def is_class_A():
        print("Nope")

请注意,在 A 类和其他类中实现的这两个函数都很长,而且更复杂。

我想到了2个解决方案,以避免BC实现中的重复:

在课堂上使用C:

def is_class_A():
    return B.is_class_A()

我不确定这将如何发挥作用,因为C 的对象不是B 的对象。而且我没有在这里传递任何self,所以我看不出这是如何工作的,也许类似的东西可以?

下一个解决方案是使用另一个遗产:

class C(B)

这并不总是有效,因为并非总是可行(如果它们具有不同的属性)并且可能不符合设计目的。

到目前为止,我最好的尝试是使用另一个类:

class BC(A):
    def is_class_A():
        print("Nope")

class B(BC):
    pass

class C(BC):
    pass

你怎么看?还有一些想法?也许是一些不涉及程序设计的更技术性的东西?

谢谢。

【问题讨论】:

  • 我认为您的前两个解决方案很糟糕,因为它们混合了与层次结构无关的类的功能,正如您所说(“可能不符合设计目的”)。只要您的类层次结构没有变得太深,中间类BC 就不是一个坏主意。只要您不为每个常见功能引入一个层次结构级别,就可以了。您还可以查看 Python 中的多重继承。
  • 我熟悉多重继承。您建议在其中固有B,C 都有一个新类,并在那里实现它?但在我的函数中,我可能会使用A 拥有的许多属性.. 听起来很复杂
  • 您可以在单独的类Z 中定义您的isClassA 覆盖,然后使用class B(Z, A): ...。请注意,Z 必须先出现,以确保优先使用Z.isClassA 而不是A.isClassA。不过,我不确定我是否真的喜欢这个主意;混入通常会添加新功能,而不是覆盖现有功能。我想我也会选择中级BC 课程。不过,我不知道您是否真的可以根据这个示例做出正确的设计决策:它太抽象了。

标签: python inheritance overriding code-duplication


【解决方案1】:

一种选择是在全局范围内定义一次替代方法,然后直接进行类属性分配。

class A:
    def is_class_A(self):
        print("We are in class A")


def alt_is_class_A(self):
    print("Nope")


class B(A):
    is_class_A = alt_is_class_A


class C(A):
    is_class_A = alt_is_class_A


class D(A):
    pass  # No override

分配也可以由装饰器处理:

def mod_it(cls):
    cls.is_class_A = alt_is_class_A


@mod_it
class B(A):
    pass


@mod_it
class C(A):
    pass


# No override
class D(A):
    pass

或通过A.__init_subclass__:

class A:
    def is_class_A(self):
        print("We are in class A")

    def __init_subclass__(cls, is_class_A=None):
        super().__init_subclass__()
        if is_class_A is not None:
            cls.is_class_A = is_class_A


def alt_is_class_A(self):
    print("Nope")


class B(A, is_class_A=alt_is_class_A):
    pass


class C(A, is_class_A=alt_is_class_A):
    pass


# No override 
class D(A):
    pass

【讨论】:

  • 如果我想在函数中使用一些属性,那将如何与全局函数一起使用?
  • 属性通过第一个参数访问,就像函数在class 语句中声明一样。
  • 方法只是一个类属性,其值为functionclassmethodstaticmethod。 (根据descriptor protocol,实际调用的是属性__get__ 方法的结果;只要您不使用非局部变量,实际定义属性值的位置并不重要在函数体中。)
  • 在一个复杂的非常OO的程序中使用全局函数有点奇怪,但它可以在不涉及设计的情况下工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-18
  • 2021-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-21
相关资源
最近更新 更多