【问题标题】:Overwriting parent function in multiple children在多个孩子中覆盖父函数
【发布时间】:2018-03-06 23:30:04
【问题描述】:

我有几个想要使用的子类,但它们都从它们的父类继承了一个方法,该方法的行为并不完全符合我的需要。

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),所以我想让我的所有包装器尽可能薄。在根据需要更改父类的同时获取我的两个子类的功能的最简洁/最 Pythonic 的方法是什么?

到目前为止我的想法:

创建一个从父类继承的新类,它会覆盖我不喜欢的函数,然后为从新类和子类继承的子类创建包装类。

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. 用于两个子类的语法是否正确?它适用于我,但让它们除了继承和传递之外什么都不做似乎有点奇怪。
  3. 让我的新父母继承前一位父母是正确的做法吗?代码在没有parentClassnewParentClass 之间的继承的情况下为孩子运行(例如def newParentClass():),但是如果有人试图创建newParentClass() 的实例,则该函数将不起作用,因为它使用了不存在于那个班级(value)。如果我假设永远不会使用该类,那可以吗?

【问题讨论】:

  • 为什么不覆盖child1和child2中的annoying_funct
  • 1) child1child2 都是 scikit-learn 函数,因此 newChild1newChild2 将是必要的 2) 更改 annoying_funct 两次似乎是多余的同样的事情,特别是因为annoying_funct 是大约 200 行相当复杂的代码,我不想在两个不同的地方修复错误。

标签: python-3.x inheritance multiple-inheritance


【解决方案1】:

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

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

此解决方案的唯一缺点是,当您向需要原始 Parent 类的函数提供新的父类或子类时,它们可能无法工作,因为它们可能使用 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. 操作现有的父类

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

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. 在继承父类之前向父类添加一个行为良好的新方法。

如果你想保持当前的行为并且不希望你现有的代码或包依赖于父类中断,你当然不应该覆盖父类中的annoying_funct。所以你应该定义一个行为良好的函数并在子类中使用它。

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'

【讨论】:

  • 谢谢,它们看起来都很有趣。你能添加任何你看到的优点或潜在的缺点吗?很难说为什么我会选择做一个而不是其他的。我还注意到您有 Child1Child2 从父级继承并通过。他们如何从导入的库中获取other_child1()other_child2() 函数?
  • 感谢更新,但这仍然无法处理来自Child1Child2 的函数。库中的子类有一堆我需要的属性和方法,这段代码只是覆盖了这些类并使子类成为父类的副本。对于方法 2,我尝试定义 class NewChild1(ParentClass, Child1),但它无法创建 MRO,并且 class NewChild1(Child1, ParentClass) 离开了 annoying_funct(),因为它在 newChildClass 的库中。简而言之,它似乎不起作用。
【解决方案2】:

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

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”,清楚地表明该类并非旨在独立存在,而是旨在为另一个类添加功能。因此,AnnoyMixin 不需要从 ParentClass 继承,从而简化了 NewChild 类的继承。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    相关资源
    最近更新 更多