![](/img/trans.png)
[英]Accidentally calling an ovverriden method from base class's __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__()
然后完成对象构造。 这也类似于具有setup
, run
和teardown
功能的单元测试。
我可能仍然没有完全理解,但这似乎做了我想(你想要的):
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.