用 super() 装饰子类的 __init__ 方法
Posted
技术标签:
【中文标题】用 super() 装饰子类的 __init__ 方法【英文标题】:Decorating a child class's __init__ method with super() 【发布时间】:2015-12-06 02:22:34 【问题描述】:我的班级层次结构是这样设置的,每个孩子的__init__()
必须将self._init_has_run()
设置为False
,调用父母的__init__()
,然后自己做__init__()
,最后将self._init_has_run()
设置为@987654327 @。我有以下代码:
class Parent:
def __init__(self, arg1, arg2):
pass # do stuff
def init(cls, fun):
def decorated_init(self, *args, **kwargs):
self._init_has_run = False
x = super()
super().__init__(*args, **kwargs)
fun(self, *args, **kwargs)
self._init_has_run = True
return decorated_init
class Child(Parent):
@Parent.init
def __init__(self, arg1, arg2):
pass # do stuff
由于有许多子类遵循与__init__()
相同的一般模式,而且我不知道如何使用元类,所以我使用装饰器来整合重复逻辑,然后仅将该装饰器应用于所有后代__init__()
方法。
Python 抛出以下内容:
File "filename.py", line 82, in decorated_init
super().__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters
我通过调试器确认self._init_has_run
的切换工作正常并且super()
正在解析为Parent 类,但是当装饰器尝试调用super().__init__(*args, **kwargs)
时,为什么Python 会尝试调用object.__init__()
?
【问题讨论】:
【参考方案1】:您可以轻松地使用 元类 来做一些 pre/post-init 的事情。考虑这个例子:
class Meta(type):
def __new__(meta, *args):
# This is something like 'class constructor'.
# It is called once for every new class definition.
# It sets default value of '_init_has_run' for all new objects.
# This is analog to `class Foo: _init_has_run = False`:
# new objects will all have _init_has_run set to False by default.
cls = super(Parent, meta).__new__(meta, *args)
cls._init_has_run = False
return cls
def __call__(cls, *args, **kwargs):
# This is called each time you create new object.
# It will run new object's constructor
# and change _init_has_run to False.
obj = type.__call__(cls, *args, **kwargs)
obj._init_has_run = True
return obj
class Child:
__metaclass__ = Meta
def __init__(self):
print 'init:', self._init_has_run
def foo(self):
print 'foo:', self._init_has_run
a = Child()
a.foo()
a = Child()
a.foo()
输出:
init: False
foo: True
init: False
foo: True
希望这会有所帮助!
【讨论】:
我无法将您的答案标记为已接受,因为您提供的示例没有解决我的问题,但它很有帮助,所以我绝对赞成。谢谢。 佩德罗,你可以描述一下还缺少什么,我会努力改进我的答案;)以上是关于用 super() 装饰子类的 __init__ 方法的主要内容,如果未能解决你的问题,请参考以下文章
Python3基础 super层层调用父类的__init__方法 子类的__init__覆盖了父类的__init__的解决方法
Python3基础 super 子类调用父类的__init__