调用超级init的python decorator

调用超级init的python decorator,python,reflection,decorator,Python,Reflection,Decorator,我正在尝试制作一个自动调用父类init的装饰器。它与单一继承一起工作,但当我尝试链接效果时,会出现堆栈溢出错误。有人能解释(a)为什么会发生这种情况,以及(b)如何实现我想要实现的目标吗 def init(__init): def wrapper(self, *args, **kwargs): self.__class__.__bases__[0].__init__(self) __init(self) return wrapper class

我正在尝试制作一个自动调用父类init的装饰器。它与单一继承一起工作,但当我尝试链接效果时,会出现堆栈溢出错误。有人能解释(a)为什么会发生这种情况,以及(b)如何实现我想要实现的目标吗

def init(__init):
    def wrapper(self, *args, **kwargs):
        self.__class__.__bases__[0].__init__(self)
        __init(self)
    return wrapper

class Base:
    def __init__(self):
        print("base init")


class Parent(Base):
    @init
    def __init__(self):
        print("parent init")

class Child(Parent):
    @init
    def __init__(self):
        print("child init")

a = Parent() #works
#c = Child() #stack overflow

正确的方法

正确的方法是直接在代码中调用父初始值设定项。在Python 3中:

super().__init__()
在Python 2中:

super(Parent, self).__init__()

错误

不过,为了回答您眼前的问题,无限递归的发生是因为您如何获得父对象:

self.__class__.__bases__[0]
self
将不会停止作为
Child
的实例,无论您调用
wrapper
函数多少次。您最终会无限期地调用
父类。\uuuu init\uuuu(self)
,因为父类从未更改

走错了路

您可能希望找到定义当前正在调用的
\uuuu init\uuu
方法的类,并获取该方法的父类@AlexMartelli在其中提供了一个函数,用于执行此操作或Python,我在这里逐字复制:

import inspect

def get_class_that_defined_method(meth):
    for cls in inspect.getmro(meth.im_class):
        if meth.__name__ in cls.__dict__: 
            return cls
    return None
如果您使用的是Python 3,请改用:


再说一遍。请不要这样做。可能有很多我没有提到的角落案例会来咬你,从
\uuuuuu base\uuuuu0]
开始。只需使用
super
即可。无论如何,这是一个经过深思熟虑的同一想法的更好版本。

正确的方法

正确的方法是直接在代码中调用父初始值设定项。在Python 3中:

super().__init__()
在Python 2中:

super(Parent, self).__init__()

错误

不过,为了回答您眼前的问题,无限递归的发生是因为您如何获得父对象:

self.__class__.__bases__[0]
self
将不会停止作为
Child
的实例,无论您调用
wrapper
函数多少次。您最终会无限期地调用
父类。\uuuu init\uuuu(self)
,因为父类从未更改

走错了路

您可能希望找到定义当前正在调用的
\uuuu init\uuu
方法的类,并获取该方法的父类@AlexMartelli在其中提供了一个函数,用于执行此操作或Python,我在这里逐字复制:

import inspect

def get_class_that_defined_method(meth):
    for cls in inspect.getmro(meth.im_class):
        if meth.__name__ in cls.__dict__: 
            return cls
    return None
如果您使用的是Python 3,请改用:


再说一遍。请不要这样做。可能有很多我没有提到的角落案例会来咬你,从
\uuuuuu base\uuuuu0]
开始。只需使用
super
即可。无论如何,这是一个经过深思熟虑的版本。看看第二种情况下的自我是什么。它将始终是
Parent
,因为
self
始终是
Child
的一个实例,无论您对它调用什么方法。您希望对包含您正在调用的
\u init
的类进行引用。这将确保您的递归最终终止。此装饰程序的实际意义是什么???不要费心尝试使此装饰程序工作。这将是一次充满陷阱的艰难旅程。只需像其他人一样在构造函数中调用父级
\uuuuu init\uuuu
。反正只比键入
@init
长几个字符。@Rawing。我希望我在回答中抓住了你的情绪。看看第二种情况是什么。它将始终是
Parent
,因为
self
始终是
Child
的一个实例,无论您对它调用什么方法。您希望对包含您正在调用的
\u init
的类进行引用。这将确保您的递归最终终止。此装饰程序的实际意义是什么???不要费心尝试使此装饰程序工作。这将是一次充满陷阱的艰难旅程。只需像其他人一样在构造函数中调用父级
\uuuuu init\uuuu
。反正只比键入
@init
长几个字符。@Rawing。我希望我的回答能抓住你的感情。