有时候需要像Java一样一个类只允许其生成一个类实例。比如设计一个打印机程序,一台计算机可以连接若干台打印机,但是同一份文件只允许一台打印机输出,避免重复打印。
Java实现单例的最简单方法:
public class PrintProgrammer:
{
private static PrintProgrammer SingleTo = null;
private void PrinterProgrammer() {}
public static getInstance(){
if (SingleTo == null) {
SingleTo = new PrinterProgrammer()
}
return SingleTo
}
}
其实Java的单例说白了很简单,就是把构造方法的权限设置为private,这样只有在类内才能访问,外界无法进行更改。然后用public静态方法进行判断是否已经有了类实例。
那么问题来了,Python没有Java的这种访问权限:public、protected、default、private!就无法实现单例模式了吗?当然不是的,类似Python这种动态语言,本身隐藏了很多实现细节,有些“高级”的类方法不是没有,而是不常有。
我们都知道Python是在特殊方法__init__
中生成实例属性的,但实际上调用__init__
方法之前实例已经生成了,这就是__new__
方法。当生成实例的时候,__new__
方法最先被调用,然后才是__init__
方法。
__new__
特殊方法第一个形参是cls,是类本身,而不是self(实例)。它必须有return值,这个返回值就是类的实例,返回给__init__
的第一个参数,现在知道为什么__init__
方法的第一个参数是self了吧。
class MyCls(object):
def __new__(cls, name, age):
print "__new__ method, name: {0} age:{1}\r\n".format(name, age)
return super(MyCls, cls).__new__(cls, name, age)
def __init__(self, name, age):
self.name = name
self.age = age
print "__init__ calling"
i = MyCls("bob", 22)
>>> __new__ metho, name: bob age:22
>>> __init__ calling
如果我们要继承一些内置的不可变的类,对其进行一些更改,比如说把传入的signed 类型(当然这是C中的叫法)初始化成unsigned类型。
class MInt(int, object):
def __init__(self, num):
super(MInt, self).__init__(abs(num))
i = MInt(-9)
>>> -9
我们发现并没有什么卵用,这时候就应该使用__new__
方法对其进行初始化。
class MInt(int):
def __new__(cls, num):
return super(MInt, cls).__new__(cls, abs(num))
i = MInt(-9)
print i
>>> 9
Note:__new__
方法一定要return,因为这是返回类的实例。
下面我们利用它来模拟Java中的单例:
class CLS(object):
def __init__(self, num):
self.num = num
def __new__(cls, num):
if not hasattr(cls, "instance"):
cls.instance = super(CLS, cls).__new__(cls)
return cls.instance
a = CLS(9)
b = CLS(10)
print a
print b
print CLS.instance
print a.num
print b.num
print a is b is CLS.instance
>>> <__main__.CLS object at 0x02C03290>
>>> <__main__.CLS object at 0x02C03290>
>>> <__main__.CLS object at 0x02C03290>
>>> 10
>>> 10
>>> True