这是我在几种语言中遗漏的功能,并且想知道是否有人知道如何在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__()
然后对象构造完成。这与使用setup
,run
和teardown
函数的单元测试类似。
答案 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
类中,因为所有逻辑都可以放在工厂函数中。