最近我读到关于如何使一个单身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
你能解释一下一步这里发生了一步,我理解为什么会发生递归的原因?
问题是,通过写super(MyClass, self).__init__(text)
,你说使用超级相对于任何类MyClass
是指在时间super
被调用。 但装饰取代MyClass
有其自身的子类。 所以,当你原来__init__
方法被称为MyClass
,实际上是指它定义了执行方法的类的子类。
要说它一步一步,我要调用原始类(如写入源) OrigMyClass
,并将得到的版本(装饰后) DecMyClass
。 我将使用MyClass
执行过程中只是作为一个变量,因为它的意义的变化。
你定义一个__init__
的方法OrigMyClass
,但__init__
方法调用super(MyClass, self)
,没有super(OrigMyClass, self)
。 因此,有什么方法实际上将被称为取决于什么MyClass
指的是在方法被调用的时间 。 的值MyClass
在执行时像任何其他变量抬头; 把它放在里面super
电话或内部__init__
方法不会奇迹般地将其绑定到它正好是当你把它写在类; 当他们被称为,它们被定义并不是当函数的变量进行评估。
在装饰上运行。 装饰器定义了一类新DecMyClass
作为的子类OrigMyClass
。 DecMyClass
定义__init__
调用super(DecMyClass, self)
。
装饰运行后,这个名字MyClass
是绑定到类DecMyClass
。 请注意,这意味着,当super(MyClass, self)
调用后执行时,它会做super(DecMyClass, self)
。
当你做MyClass(111)
实例化的对象DecMyClass
。 DecMyClass.__init__
调用super(DecMyClass, self).__init__
。 该执行OrigMyClass.__init__
。
OrigMyClass.__init__
调用super(MyClass, self).__init__
。 因为MyClass
指DecMyClass
,这是一样的super(DecMyClass, self).__init__
。 但是DecMyClass
是的子类OrigMyClass
。 关键的一点是,因为MyClass
指DecMyClass
, OrigMyClass
实际上是对自身的一个子类调用超。
因此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
。 的超Sub
是Super
,所以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
执行调用。 如图这个例子中,可变甚至没有在定义的方法中的时间存在; 该值在调用方法时抬头。