在多个 children 中覆盖 parent 函数

Overwriting parent function in multiple children

我有几个 child class 我想使用,但它们都从它们的 parent 继承了一个方法,但它的行为并不符合我的需要到.

class ParentClass():
    def __init__(self, value):
        self.value = value
    def annoying_funct(self):
        print("I don't do quite what's needed and print {0}".format(self.value + 1))
    def other_parent(self):
        print("I do other useful things my children inherit")

class Child1(ParentClass):
    def __init__(self, value, new_value1):
        super(Child1, self).__init__(value)
        self.new_value1 = new_value1
    def other_child1(self):
        print("I do useful child things")

class Child2(ParentClass):
    def __init__(self, value, new_value2):
        super(Child2, self).__init__(value)
        self.new_value2 = new_value2
    def other_child2(self):
        print("I do other useful child things")

我想像这样覆盖 annoying_funct()

def annoying_funct():
    print("I behave the way I am needed to and print {0}".format(self.value))

ParentClassChild1Child2 来自一个非常复杂的库 (scikit-learn),因此我想使所有包装器尽可能薄。在根据需要更改 parent class 的同时获得我的两个 child class 的功能的 cleanest/most pythonic 方式是什么?

到目前为止我的想法:

创建一个继承自 parent 的新 class,它会覆盖我不喜欢的函数,然后为 children 制作包装器 classes继承自新的 class 和 child classes.

class NewParentClass(ParentClass):
    def annoying_funct(self):
        print("I behave the way I am needed to and print {0}".format(self.value))

class NewChild1(NewParentClass, Child1):
    pass

class NewChild2(NewParentClass, Child2):
    pass

我的困惑领域:

  1. 这是正确的方法吗?这似乎有点奇怪和笨拙。有更简洁的方法吗?
  2. 这两个 child class 使用的语法是否正确?它为我运行,但让他们只继承和传递似乎有点奇怪。
  3. 让我的新 parent 继承以前的 parent 是正确的做法吗?代码为 children 运行,没有 parentClassnewParentClass 之间的继承(例如 def newParentClass():),但是如果有人试图创建 newParentClass() 的实例该函数不起作用,因为它使用了 class (value) 中不存在的属性。如果我假设永远不会使用 class 可以吗?

有几种方法可以满足您的要求。

  1. 创建一个新的 class 从父 class 继承,然后将其用作新的父 class。

此解决方案的唯一缺点是,当您将新的父项或子项 class 提供给需要原始父项 class 的函数时,可能无法正常工作,因为它们可能会使用 annoying_funct并依赖于烦人的行为。

class NewParentClass:
    def annoying_funct(self):
       print("I behave the way I am needed to and print {0}".format(self.value))

class NewChild1(NewParentClass):
    pass

class NewChild2(NewParentClass):
    pass
  1. 操纵现有父级class

这是我想使用的解决方案,因为它通过用一个表现良好的替代它来完全破坏 annoying_funct,再次购买,其他需要前者 annoying_funct 的方法和功能可能会失败.好的一面是,您不需要创建另一个父项 class 和子项,因此您的代码会更加优雅。

class ParentClass():
    ...
    def annoying_funct(self):
        print("I don't do quite what's needed and print {0}".format(self.value + 1))
   ...


def well_behaving_func(s):
    print("Good")

# Dynamically change the class method    
ParentClass.annoying_func = well_behaving_func

class Child1(Parent):
    pass

class Child2(Parent):
    pass

c = Child1()
c.annoying_funct() # prints 'Good'
  1. 在从父 class 继承之前添加一个行为良好的新方法。

如果您想保持当前的行为并且不希望依赖父 class 的现有代码或包中断,您当然不应该覆盖父 [=] 中的 annoying_funct 37=]。所以你应该定义一个行为良好的函数并在子 classes.

中使用它
class ParentClass():
    ...
    def annoying_funct(self):
        print("I don't do quite what's needed and print {0}".format(self.value + 1))
   ...   

def well_behaving_func(s):
    print("Good")

# Dynamically change the class method    
ParentClass.well_behaving_func = well_behaving_func

class Child1(Parent):
    pass

class Child2(Parent):
    pass

c = Child1()
# use 'well_behaving_func', not the annoying one
c.well_behaving_func() # prints 'Good'

我最终做的是使用 mixin 的概念将我的新功能添加到子 classes。结果代码如下:

class AnnoyMixin:
    def well_behaving_func(self):
        print("I behave the way I am needed to and print {0}".format(self.value))

class NewChild1(AnnoyMixin, Child1):
    def annoying_funct(self):
        return well_behaving_func(self)

class NewChild2(AnnoyMixin, Child2):
    def annoying_funct(self):
        return well_behaving_func(self)

在功能上,这与我在问题中提出的代码的行为基本相同,但修改有助于提高可读性。首先,通过将新父级命名为 "Mixin",可以清楚地表明此 class 并非设计用于独立存在,而是旨在向另一个 class 添加功能。因此,AnnoyMixin 不需要从 ParentClass 继承,简化了 NewChild class 的继承。

其次,我们创建了新函数 well_behaving_func,而不是覆盖 AnnoyMixin 中的 annoying_funct。然后是 NewChild classes 作业通过调用 well_behaving_func 覆盖 annoying_funct。从功能上讲,这与 AnnoyMixin 已覆盖 annoying_funct 的工作方式大致相同,但通过这种方式,阅读代码的人会更清楚 annoying_functNewChild classes.