Python 类的初始化分为两步
我们常用的 __init__ 函数实际上是第二步,而第一步即是 __new__ 函数,一个 __new__ 函数默认实现为:
class Testclass(object):
def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)
def __init__(self, params):
pass
这里 object.__new__(cls, *args, **kwargs) 返回的即 __init__ 中的实例,我们对上面代码进行修改,更直观的来看一下一个对象初始化的过程:
class Testclass(object):
def __new__(cls, *args, **kwargs):
print 'in __new__'
print cls
instance = object.__new__(cls, *args, **kwargs)
print 'out __new__'
return instance
def __init__(self):
print 'in __init__'
print self
print 'out __init__'
if __name__ == '__main__':
t = Testclass()
测试结果:
in __new__
out __new__
in __init__
<__main__.Testclass object at 0x019AC2D0>
out __init__
从上面测试中我们可以看到,在 __new__ 中,cls 为构建的类,object.__new__ 返回一个类实例,然后该实例会通过 self 传递给 __init__,然后对实例对象进行初始化
对以上过程有了一个认识后,我们就可以构建一个单件模式了。对于单件,当一个类已经创建了实例,后续就不再创建该类的实例,而是直接返回已创建的实例。基于此,我们对 __new__ 进行重写,如下:
class Test(object):
__instance = None
__firstinit = 1
def __new__(cls, *args, **kwargs):
if Test.__instance == None:
Test.__instance = object.__new__(cls, *args, **kwargs)
return Test.__instance
def __init__(self):
if not Test.__firstinit:
return
Test.__firstinit = 0
if __name__ == "__main__":
a = Test()
b = Test()
print a
print b
上例中我们将类的实例保存到一个类属性 __instance 中,一旦类属性不为 None,我们就不再调用 __new__,而是直接返回 __instance。另外为避免每次调用 Test() 都会执行一遍实例初始化,我们引入了一个 __firstinit 的类属性,执行结果:
<__main__.Test object at 0x019FC930>
<__main__.Test object at 0x019FC930>
我们可以看到 a 和 b 是相同的实例。
在进行单例模式类继承时,需要注意,子类的 __new__ 在创建实例时,不能调用父类的 __new__,否则会直接通过判断父类的 __instance 属性,应该写成下面方式:
class TestChild(Test):
__instance = None
def __new__(cls, *args, **kwargs):
if TestChild.__instance == None:
TestChild.__instance = object.__new__(cls, *args, **kwargs)
return TestChild.__instance
有兴趣的朋友可以尝试把 object 改为 Test 试一下,创建出来的实例与 Test 的实例是相同的实例,这里就不再进行演示了
当然除了,这种方式,还有使用装饰器,__metaclass__ 等方式来实现单例模式的,有兴趣的童鞋可以参考这篇博文
http://blog.csdn.net/karldoenitz/article/details/23467221