python设计模式中的 单例模式:单例模式可以通过__new__ 方法实现,而__new__ 方法一般用于继承不可变对象。
1、可变不可变对象
python中有可变对象和不可变对象两种。前者创建后,可改变,地址却不会改变,后者创建后都不能改变,一旦被改变了,就会产生一个新的对象。
class Mylist(object):
def __init__(self,mylist_id,name=[ ]):
self.mylist_id= mylist_id
self.name= name
def add_name(self,name):
self.name.append(name)
mylist1= Mylist(1)
mylist1.add_name('zhangsan')
print(id(mylist1))
print(mylist1.name)
mylist2= Mylist(2)
mylist2.add_name('lisi')
print(id(mylist2))
print(mylist2.name)
print(id(mylist1.name))
print(id(mylist2.name))
结果图:
有结果可知mylist1和mylist2的id号不一样,在不同地址,但是mylist2可以在1的基础上添加新的东西。这是因为 __init__函数在被创建的时候默认参数的值已经生成了往后继续用的时候在是前者的基础上,可以看到两个mylist.name的地址是一样的,所添加的名字在同一个地址里。
class Mylist(object):
def __init__(self,mylist_id):
self.mylist_id= mylist_id
self.name= []
def add_name(self,name):
self.name.append(name)
mylist1= Mylist(1)
mylist1.add_name('zhangsan')
print(id(mylist1))
print(mylist1.name)
mylist2= Mylist(2)
mylist2.add_name('lisi')
print(id(mylist2))
print(mylist2.name)
print(id(mylist1.name))
print(id(mylist2.name))
结果图:
我们在__init__函数里面去掉name这个参数,self.name = [ ],相当于这个地方是空的,因为并没有传参。只有当调用add_name函数的时候在空列表里面添加名字,这时候不会因为创建__init__函数而产生默认缓存,导致每次在添加新内容都会在之前的缓存里面添加。这时两个mylist.name的地址也是不一样的。
2、__new__方法
这里涉及到一个__new__方法的使用,因为new方法正式用于继承一些不可变的class时,__new__函数是分配地址空间的,创建对象的第一步,而__init__是初始化对象的,属于第二步。__new__被定义为静态方法,需要传参数。需要返回值,返回的是实例化的实例,并且返回值是作为__init__的self参数传入__init__函数。
class Test(object):
def __init__(self):
print('__init__()')
def __new__(cls):
print('__new__()')
return object.__new__(cls)
if __name__== '__main__':
test= Test()
结果图:
由此可以看出,实例化类时,先调用的是__new__函数,然后才是__init__函数
3、通过__new_-方法实现单例模式
单例模式:常见的一种软件设计模式,主要目的是确保某一个类只有一个实例存在。
__new__方法可以用来实现设计模式中的单例模式,因为每次初始化实例对象的时候先调用的是__new__ 方法,我们需要对它重写保证实现这个类只有一个实例存在。
class Singleton(object):
def __new__(cls):
# 用 hasattr 判断类里是否有实例,如果没有继承之前的一个实例,如果没有返回一个实例。
if not hasattr(cls,'instance'):
cls.instance= object.__new__(cls)
return cls.instance
# def __init__(self):
# pass
test1= Singleton()
test2= Singleton()
print(test1)
print(test2)
print (test1is test2)
结果图:
通过__new__ 方法的重写,虽然实例化两次,但是是同一个地址里面,保证了只有一个实例
我们把__new__ 方法注释掉,直接用__init__方法:
class Singleton(object):
# def __new__(cls):
# # 用 hasattr 判断类里是否有实例,如果没有继承之前的一个实例,如果没有返回一个实例。
# if not hasattr(cls, 'instance'):
# cls.instance= object.__new__(cls)
# return cls.instance
def __init__(self):
pass
test1= Singleton()
test2= Singleton()
print(test1)
print(test2)
print (test1is test2)
结果图:
没有使用__new__方法重写,直接用__init__时,就没办法保证有唯一的实例,实例化几次就会产生几个地址,并且不相同。
class Singleton(object):
def __new__(cls):
# 用 hasattr 判断类里是否有实例,如果没有继承之前的一个实例,如果没有返回一个实例。
if not hasattr(cls,'instance'):
cls.instance= object.__new__(cls)
return cls.instance
def __init__(self):
pass
def action(self):
return id(self)
test1= Singleton()
test2= Singleton()
print(test1.action())
print(test2.action())
再试一次,增加一个新的方法 action( ),用来返回地址。通过结果可以看到,实例化两次,action( )方法实现两次,输出两次结果,但两次输出的地址还是一样的。很明显如果注释掉__new__方法,那么地址是肯定不一样的。这里单例模式就起到作用了。避免了同一个内容被多次使用后,每次都要占用不同的地址,浪费了资源。
以上就是python的单例模式。