开发者学堂课程【Python 入门 2020年版:单例设计模式】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/639/detail/10383
单例设计模式
单例设计模式
单例设计模式是保证在全局里只有一个对象,例如在电脑的操作系统里只有一个回收站。
class Singleton(object) :
def _new__(cls,*args,**kwargs):
pass
def __init__(self, a, b):
self.a = a
self.b = b
# 调用 _new_ 方法申请内存
# 如果不重写 _new_ 方法,会调用 object 的 _new_ 方法
# object 的 _new_ 方法会申请内存
# 如果重写了 _new_ 方法,需要自己手动的申请内存
s1 = singleton(‘呵呵’,’嘿嘿嘿‘)
s2 = Singleton(‘哈哈‘,‘嘻嘻嘻’)
print(s1 is s2) # True
创建两个对象 s1、s2,打印 ‘s1 is s2’ 发现结果是 False,单例的目的就是通过一些代码把 false 变成 true。
对象会首先调用 __new__ 方法申请内存然后再调用 __init__ 方法向内存中填入数据,s1、s2 调用方法时会同时申请内存,但他们申请的内存地址是不一样的,如果想要 s1、s2 申请的内存地址相同应该只允许 __new__ 方法被调用一次。
现在如果直接打印 s1、s2 结果会显示他们都是 none,如果不重写 __new__ 方法,会调用 object 的 __new__ 方法,object 的 new 方法会申请内存,如果重写了 new 方法,需要自己手动的中请内存。
class singleton(object):
def _new_(cls,*args,**kwargs ):
# 内存只需创建一个对象,并把对象的类型设置为 cls
cls.instance = object._new__(cls)
return cls.instance
def __init_(self, a, b):
self.a = a
self.b = b
# 调用 _new_ 方法申请内存
# 如果不重写 _new_ 方法,会调用 object 的 _new_ 方法
# object的 _new_ 方法会申请内存
# 如果重写了_new_方法,需要自己手动的申请内存
s1 = singleton(‘呵呵‘,‘嘿嘿嘿’)
s2 = singleton(‘哈哈’,‘嘻嘻嘻’)
print(type(s1))
在 python 里申请内存只需创建一个对象,并把对象的类型设置为 cls,这时打印 print(type(s1))
就可以得到一个结果了。
class singleton:
instance = Nohe
# 类属性
@classmethod
def _new_(cls,*args,**kwargs ):
if cls.instance is None:
# 申请内存,创建一个对象,并把对象的类型设置为
cls.instance = object.__new__(cls)
return cls.instance
def _init__(self, a, b):
self.a = a
self.b = b
s1 = singleton(‘呵呵’,‘嘿嘿嘿‘)
s2 = singleton(‘哈哈‘,‘嘻嘻嘻‘)
print(s1 is s2) # True
现在 s1 和 s2 依然不是一个对象,因为 s1、s2 都需要调用 __new__ 方法都会创建一个新的地址,现在只需要判断一下让他们只调用一次即可。在每一次创建对象时判断类对象是否为空,如果为空申请内存并且把类对象进行赋值,最后返回。
现在 s1、s2 就变成了一个对象了。
class singleton:
instance = Nohe
# 类属性
@classmethod
def _new_(cls,*args,**kwargs ):
if cls.instance is None:
# 申请内存,创建一个对象,并把对象的类型设置为
cls.instance = object.__new__(cls)
return cls.instance
def _init__(self, a, b):
self.a = a
self.b = b
s1 = singleton(‘呵呵‘,‘嘿嘿嘿’)
s2 = singleton(‘哈哈‘,‘嘻嘻嘻‘)
print(s1.a == s2.a)
print(s1.b == s2.b)]
print(s1.a, s1.b)、
打印 s1 的 a、s2 的 a 和 s1 的 b、s2 的 b 发现他们是相等的,因为他们指向同一块内存。打印 s1 的 a 和 s2 的 b 的结果是‘哈哈’、‘嘻嘻嘻’,发现 s2 把 s1 覆盖了。
s2 创建的时候没有创建成功,在运行 __new__ 之后紧接着运行 __init__ 他直接进入了__init__代码把‘嘿嘿’改成了‘哈哈’,把‘嘿嘿嘿’改成了‘嘻嘻嘻’。
class singleton:
instance = Nohe # 类属性
__is_first = True
@classmethod
def _new_(cls,*args,**kwargs ):
if cls.instance is None:
#申请内存,创建一个对象,并把对象的类型设置为
cls.instance = object.__new__(cls)
return cls.instance
def _init__(self, a, b):
if self.__is_first:
self.a = a
self.b = b
self.__is_first = False
s1 = singleton(‘呵呵‘,‘嘿嘿嘿‘)
s2 = singleton(‘哈哈’,‘嘻嘻嘻’)
s3 = singleton(‘嗄嗄‘,‘嘤嘤嘤‘)
再创建一个 s3 会发现结果变成了 s3 的内容,因为他再次运行了__init__ 。
例如在操作系统里再创建了一个回收站,虽然没有创建成功但是他改
变了回收站的属性,第一次创建的对象就相当于没被创建。想要第一
个对象不被后面的对象替换,只需再添加一个判断即可。
S = singleton 每一次都会调用 __init__ 方法,__init__ 内存空间里只有 a 属性和 b属性没有 __is_first 属性,所以他会向上找到 __is_first 。
因为类属性只能通过类对象来修改所以之后self.__is_first = False 会在 __init__ 里加入一个 __is_first = False。