在基类__init__的子类__init__之后调用基类方法?

时间:2017-07-09 20:57:31

标签: python python-3.x class constructor

这是我在几种语言中遗漏的功能,并且想知道是否有人知道如何在Python中完成它。

我的想法是我有一个基类:

class Base(object):
    def __init__(self):
        self.my_data = 0
    def my_rebind_function(self):
        pass

和派生类:

class Child(Base):
    def __init__(self):
        super().__init__(self)
        # Do some stuff here
        self.my_rebind_function() # <==== This is the line I want to get rid of
    def my_rebind_function(self):
        # Do stuff with self.my_data

从上面可以看出,我有一个反弹功能,我希望在<{strong> Child.__init__完成其工作后称为。我希望这对所有继承的类都完成,所以如果它是由基类执行的话会很棒,所以我不必在每个子类中重新键入该行。

如果语言具有类似__finally__的函数,操作类似于异常操作,那将会很好。也就是说,它应该在所有__init__ - 所有派生类的函数运行之后运行,这将是很好的。因此,呼叫顺序类似于:

Base1.__init__()
...
BaseN.__init__()
LeafChild.__init__()
LeafChild.__finally__()
BaseN.__finally__()
...
Base1.__finally__()

然后对象构造完成。这与使用setuprunteardown函数的单元测试类似。

3 个答案:

答案 0 :(得分:2)

我可能仍然没有完全理解,但这似乎做了我想(你想要的):

class Base(object):
    def __init__(self):
        print("Base.__init__() called")
        self.my_data = 0
        self.other_stuff()
        self.my_rebind_function()

    def other_stuff(self):
        """ empty """

    def my_rebind_function(self):
        """ empty """

class Child(Base):
    def __init__(self):
        super(Child, self).__init__()

    def other_stuff(self):
        print("In Child.other_stuff() doing other stuff I want done in Child class")

    def my_rebind_function(self):
        print("In Child.my_rebind_function() doing stuff with self.my_data")

child = Child()

输出:

Base.__init__() called
In Child.other_stuff() doing other stuff I want done in Child class
In Child.my_rebind_function() doing stuff with self.my_data

答案 1 :(得分:1)

您可以使用类似的元类执行此操作:

    class Meta(type):
        def __call__(cls, *args, **kwargs):
            print("start Meta.__call__")
            instance = super().__call__(*args, **kwargs)
            instance.my_rebind_function()
            print("end Meta.__call__\n")
            return instance


    class Base(metaclass=Meta):
        def __init__(self):
            print("Base.__init__()")
            self.my_data = 0

        def my_rebind_function(self):
            pass


    class Child(Base):
        def __init__(self):
            super().__init__()
            print("Child.__init__()")

        def my_rebind_function(self):
            print("Child.my_rebind_function")
            # Do stuff with self.my_data
            self.my_data = 999


    if __name__ == '__main__':
        c = Child()
        print(c.my_data)

通过覆盖Metaclass .__ call__,你可以在类树的所有__init __(和__new__)方法在返回实例之前运行时挂钩。这是调用重新绑定功能的地方。为了理解调用顺序,我添加了一些打印语句。输出将如下所示:

start Meta.__call__
Base.__init__()
Child.__init__()
Child.my_rebind_function
end Meta.__call__

999

如果您想继续阅读并深入了解详细信息,我可以推荐以下文章:https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/

答案 2 :(得分:0)

如果你希望在实例化继承自Base的每个类型的实例后调用“重新绑定”函数,那么我会说这个“重新绑定”函数可以在Base类之外生存(或任何继承自它的类)。

您可以拥有一个工厂函数,在您调用它时为您提供所需的对象(例如give_me_a_processed_child_object())。这个工厂函数基本上实例化一个对象,并在它返回给你之前对它做了一些事情。

将逻辑放在__init__中并不是一个好主意,因为它模糊了逻辑和意图。当您编写kid = Child()时,您不希望在后台发生很多事情,特别是那些对您刚刚创建的Child实例起作用的事情。您期望的是Child的新实例。

然而,工厂函数透明地对对象执行某些操作并将其返回给您。这样您就知道您正在获取已经处理过的实例。

最后,您希望避免将“重新绑定”方法添加到您现在可以使用的Child类中,因为所有逻辑都可以放在工厂函数中。