Chow's Notes

Python中实现单例模式的几种方法

1.使用new方法

1
2
3
4
5
6
7
8
9
10
11
class Singleton(object):
def __new__(cls,args,**kw):
if not hasattr(cls,“_instance“):
orig=super(Singleton,cls)
cls._instance=orig.__new__(cls,args,**kw)
print “Ok“
return cls._instance
class MyClass(Singleton):
def init(self,name):
self.name=name

特殊方法new是一个元构造程序,每当一个对象必须被factory类实例化时就将调用它
new方法必须返回一个类的实例,因此它可以在对象创建之前或之后修改类
因为init在子类中不会被隐式调用,所以new可以用来确定已经在整个类层次完成了初始化构造
new是对于对象状态隐式初始化需求的回应,使得可以在比init更低的一个层次上定义一个初始化,这个初始化总是会被调用
init()相比new()方法更像一个真正的构造器。随着类和类型的统一,用户可以对内建类型进行派生,因此需要一种途径来实例化不可变对象,比如派生字符串,在这种情况下解释器则调用类的new()方法,一个静态方法,并且传入的参数是在类实例化操作时生成的。new()会调用父类的new()来创建对象(向上代理)
new必须返回一个合法的实例,这样解释器在调用init()时,就可以吧这个实例作为self传给他。调用父类的new()来创建对象,正如其他语言使用new关键字一样
ps.
1.new是一个静态方法,而init是一个实例方法.
2.new方法会返回一个创建的实例,而init什么都不返回.
3.只有在new返回一个cls的实例时后面的init才能被调用.
4.当创建一个新实例时调用new,初始化一个实例时用init.

metaclass是创建类时起作用.所以我们可以分别使用metaclass,newinit来分别在类创建,实例创建和实例初始化的时候做一些小手脚.

2.装饰器版本

1
2
3
4
5
6
7
8
9
10
def singleton(cls):
instances = {}
def getinstance(*args,**kwagrs):
if cls not in instance:
instance[cls]=cls(*args,**kwagrs)
return instance[cls]
return getinstance
@singleton
class MyClass:
pass

3.共享属性

创建实例时把所有实例的dict指向同一个字典,这样它们具有相同的属性和方法.
但是创建的是两个不同的实例,共享一样的属性

1
2
3
4
5
6
7
8
9
class Borg(object):
_state = {}
def __new__(cls, *args, **kw):
ob = super(Borg, cls).__new__(cls, *args, **kw)
ob.__dict__ = cls._state
return ob
class MyClass2(Borg):
a = 1

4.另一种方法,通过代表的形式,使用递归的方式建立子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class OnlyOne:
class OnlyOne:
def init(self, arg):
self.val = arg
def str(self):
return self + self.val
instance = None
def init(self, arg):
if not OnlyOne.instance:
OnlyOne.instance = OnlyOne.OnlyOne(arg)
else:
OnlyOne.instance.val = arg
def getattr(self, name):
return getattr(self.instance, name)
x = OnlyOne(‘sausage‘)
print x
y = OnlyOne(‘eggs‘)
print y
z = OnlyOne(‘spam‘)
print z
print x
print y
print x
print y
print z
output = ‘’’
sausage
eggs
spam
spam
spam
‘’’