繁体   English   中英

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

[英]Calling base class method after child class __init__ from base class __init__?

这是我在几种语言中遗漏的一个功能,并且想知道是否有人知道如何在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

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

如果语言具有像__finally__这样的函数,操作类似于它如何操作异常,那将是很好的。 也就是说,它应该在所有__init__ -functions(所有派生类)运行之后运行,这将是很好的。 所以电话订单会是这样的:

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

然后完成对象构造。 这也类似于具有setuprunteardown功能的单元测试。

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

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

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

    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/

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM