为什么一个递归发生在这里?(Why a recursion happens here?)

2019-07-30 18:40发布

最近我读到关于如何使一个单身Python中一个有趣的讨论 。 解决的办法之一是一个棘手的装饰定义其代码中的一类,作为装饰类的替代品 :

def singleton(class_):
    class class_w(class_):
        _instance = None
        def __new__(class2, *args, **kwargs):
            if class_w._instance is None:
                class_w._instance = super(class_w, class2).__new__(class2, *args, **kwargs)
                class_w._instance._sealed = False
            return class_w._instance
        def __init__(self, *args, **kwargs):
            if self._sealed:
                return
            super(class_w, self).__init__(*args, **kwargs)
            self._sealed = True
    class_w.__name__ = class_.__name__
    return class_w

@singleton
class MyClass(object):
    def __init__(self, text):
        print text
    @classmethod
    def name(class_):
        print class_.__name__

x = MyClass(111)
x.name()
y = MyClass(222)
print id(x) == id(y)

输出是:

111     # the __init__ is called only on the 1st time
MyClass # the __name__ is preserved
True    # this is actually the same instance

据说,如果我们使用super(MyClass, self).__init__(text)__init__MyClass ,我们进入递归

我测试的确递归发生。 但是,据我了解, MyClass继承object ,所以super(MyClass, self)应该只是仅仅是object ,但事实证明, super(MyClass, self)__main__.MyClass

你能解释一下一步这里发生了一步,我理解为什么会发生递归的原因?

Answer 1:

问题是,通过写super(MyClass, self).__init__(text) ,你说使用超级相对于任何类MyClass是指在时间super被调用。 但装饰取代MyClass有其自身的子类。 所以,当你原来__init__方法被称为MyClass ,实际上是指它定义了执行方法的类的子类。

要说它一步一步,我要调用原始类(如写入源) OrigMyClass ,并将得到的版本(装饰后) DecMyClass 。 我将使用MyClass执行过程中只是作为一个变量,因为它的意义的变化。

  1. 你定义一个__init__的方法OrigMyClass ,但__init__方法调用super(MyClass, self) ,没有super(OrigMyClass, self) 。 因此,有什么方法实际上将被称为取决于什么MyClass在方法被调用的时间 。 的值MyClass在执行时像任何其他变量抬头; 把它放在里面super电话或内部__init__方法不会奇迹般地将其绑定到它正好是当你把它写在类; 当他们被称为,它们被定义并不是当函数的变量进行评估。

  2. 在装饰上运行。 装饰器定义了一类新DecMyClass作为的子类OrigMyClassDecMyClass定义__init__调用super(DecMyClass, self)

  3. 装饰运行后,这个名字MyClass是绑定到类DecMyClass 。 请注意,这意味着,当super(MyClass, self)调用后执行时,它会做super(DecMyClass, self)

  4. 当你做MyClass(111)实例化的对象DecMyClassDecMyClass.__init__调用super(DecMyClass, self).__init__ 。 该执行OrigMyClass.__init__

  5. OrigMyClass.__init__调用super(MyClass, self).__init__ 。 因为MyClassDecMyClass ,这是一样的super(DecMyClass, self).__init__ 。 但是DecMyClass是的子类OrigMyClass 。 关键的一点是,因为MyClassDecMyClassOrigMyClass实际上是对自身的一个子类调用超。

  6. 因此super(DecMyClass, self).__init__再次呼吁OrigMyClass.__init__ ,这再次调用自身,并没有穷尽的。

其效果是相同的,因为这代码,这可能使得执行路径更明显:

>>> class Super(object):
...     def __init__(self):
...         print "In super init"
...         super(Sub, self).__init__()
>>> class Sub(Super):
...     def __init__(self):
...         print "In sub init"
...         super(Sub, self).__init__()

需要注意的是Super调用super(Sub, self) 。 它试图调用父类的方法,但它试图调用父类方法Sub 。 的超SubSuper ,所以Super风再次调用自身的方法。

编辑:只是为了澄清你提到的名字,查找问题,这里有相同的结果会略有不同的例子:

>>> class Super(object):
...     def __init__(self):
...         print "In super init"
...         super(someClass, self).__init__()
>>> class Sub(Super):
...     def __init__(self):
...         print "In sub init"
...         super(Sub, self).__init__()
>>> someClass = Sub

这应该说清楚,类参数super (第一个参数,这里someClass )是不以任何方式特殊。 这只是一个普通的名字,其值在普通的时间,即当被查找在普通方式super执行调用。 如图这个例子中,可变甚至没有在定义的方法中的时间存在; 该值在调用方法时抬头。



文章来源: Why a recursion happens here?