2017-07-09 152 views
0

这是我想念几种语言的功能,并想知道是否有人有任何想法如何在Python中完成。从基类__init__的子类__init__调用基类方法?

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

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__,操作类似,它如何与例外操作这将是很好。也就是说,它应该在所有派生类的函数全部运行之后运行,这很好。所以通话顺序如下:

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

然后对象构造完成。这也是一种类似于setuprunteardown功能单元测试。

+0

要覆盖在少儿班这种方法吗? – PRMoureu

+0

不,我希望在调用所有孩子的__init __-函数后调用另一个函数。 – Robert

+0

你可以用元类来实现,albiet更复杂:\ – direprobs

回答

1

我可能还没有完全理解,但是这似乎做什么,我(觉得)你想:

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 
+0

这解决了这个问题,非常好,但是这个解决方案有一个问题。现在我必须有'other_stuff'方法,它实际上代替了'Child'类中'__init_'方法。所以,现在'Child'类的用户必须将代码从其正常位置('__init__')移动到某种新方法('other_stuff')。 – Robert

+0

Child-class的_user_赢得了它的任何代码。它的实现者只需将所需的代码放在不同的地方(方法)。对我来说听起来不是什么大不了的事...... – martineau

0

如果你想要一个“重新绑定”功能是从Base继承实例化一个类型的每个实例之后被调用,那么我会说这个“重新绑定”功能,可以住Base类(或它继承任何类)之外。

你可以有一个工厂的功能,让你当你调用它(例如give_me_a_processed_child_object()),你需要的对象。这个工厂函数基本上实例化一个对象,并在它返回给你之前做一些事情。

__init__把逻辑是不是一个好主意,因为它模糊逻辑和意图。当你编写kid = Child()时,你不会指望在后台发生很多事情,尤其是那些在刚刚创建的Child实例上发生的事情。你期望的是一个新的例子Child

一个工厂的功能,但是,透明地做了一个对象,并返回给你。这样你就知道你正在得到一个已经处理过的实例。

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

0

为此,您可以用这样的一个元类:

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) 

通过覆盖元类.__ call__你都可以__init__(和__new__)类树的方法之后的挂钩已经返回实例之前运行。这是调用你的rebind函数的地方。为了理解呼叫次序,我添加了一些打印语句。输出将是这样的:

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/