设计模式:就是经过前人总结提炼,形成对某一特殊问题的成熟解决方案,不同问题提供不同解决套路。
单例:目的时让类创建的对象在系统中只有一个实例,每一次执行类名()返回的对象,内存地址是相同的,即让类创建的对象在系统中只有一个实例。
原理:使用类名()创建一个对象时,python默认完成两件事情。第一步,应用__new__为对象创建一个内存空间(__new__是由object基类创建的内置静态方法),并返回对象的引用。接下来第二步就是将该引用传递给__init__的第一个参数,__init__开始定义实例属性。
cls是代表这个类, self是用来代表这个类的实例
学习new是为了对分配空间的方法进行改造
首先要明确为什么要重写new:object中自带new方法为实例分配内存空间并返回引用,但是不能实现让类创建的对象在系统中只有一个实例。因此,要重写new方法,使让类创建的对象在系统中只有一个实例。如果不重写new方法,使用基类object自带new方法,则当用类名创建多个实例时会给不同实例分配不同内存空间。
例如:
class Music_player(object):
def __init__(self):
print("初始化播放器")
player1 = Music_player()
print(player1)
player2 = Music_player()
print(player2)
输出结果为:
初始化播放器
<__main__.Music_player object at 0x000002280B710908>
初始化播放器
<__main__.Music_player object at 0x000002280B7109E8>
不仅多个实例时会给不同实例分配不同内存空间,而且还会调用两次初始化,这是不被允许的,接下来会慢慢改进。
**重写__new__方法:(为单例做铺垫)**注意:一定要返回对象引用!
实例:
class Music_player(object):
def __new__(cls, *args, **kwargs):
print("分配空间")
#分配内存空间
#调用父类中的方法
instance = super().__new__(cls)
#返回对象的引用
return instance
def __init__(self):
print("播放器初始化")
player = Music_player()
print(player)
输出结果:
分配空间
播放器初始化
<__main__.Music_player object at 0x0000025993780908>
注意:在观看视频时,对于super().new(cls)中的参数,大家又有不同的看法。__new__方法, 是新式类用来创建实例使用的, 传入的cls就是用来给object.__new__创建实例使用的参数, 如果没有传入cls, object根本不知道创建什么样的实例.__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供.
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
单例:
1.定义一个类属性,初始值为None,用于记录单例对象的引用。
20重写__new__方法
3.如果类属性is None,调用父类方法分配空间,并在类属性中记录结果。
4.返回类属性中记录的结果。
给创建的类的__new__中增加了判断条件。若类未被初始化,就没有实例获得内存区域,第一个实例被初始化后,第一个实例有了内存地址,就把这个地址赋给instance,之后的所有实例都使用instance中的地址。
实例:
class Music_player(object):
#记录第一个被创建的引用
instance = None
def __new__(cls, *args, **kwargs):
#1.判断雷
#1.类属性是否为空对象,是空对象说明第一个对象还未被创建
if cls.instance is None:
#2.如果对象未被创建,调用父类方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
#3.反回类属性保存的对象引用
return cls.instance
player1 = Music_player()
print(player1)
player2 = Music_player()
print(player2)
输出结果:
<__main__.Music_player object at 0x000001CB9B8254A8>
<__main__.Music_player object at 0x000001CB9B8254A8>
改进:使初始化制备调用一次。
原理:定义类属性init_flag记录初始化是否被调用,将init_flag初始化为False,表示对象还未被初始化。在__init__函数中,判断init_flag,如果为True,则return,不再执行初始化;否则执行初始化动作。
实例:
class Music_player(object):
#记录第一个被创建的引用
instance = None
init_flag = False
def __new__(cls, *args, **kwargs):
#1.判断雷
#1.类属性是否为空对象,是空对象说明第一个对象还未被创建
if cls.instance is None:
#2.如果对象未被创建,调用父类方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
#3.反回类属性保存的对象引用
return cls.instance
def __init__(self):
#判断是否执行过初始化()
if Music_player.init_flag:
return
# 如果没有执行过,执行初始化动作
print("初始化播放器")
#否则,修改类属性的标记
Music_player.init_flag = True
player1 = Music_player()
print(player1)
player2 = Music_player()
print(player2)
输出结果:
初始化播放器
<__main__.Music_player object at 0x000001DAE2940908>
<__main__.Music_player object at 0x000001DAE2940908>
初始化动作只执行了一次。