单例
目标
- 单例设计模式
__new__
方法
- Python中的单例
单例设计模式
设计模式
- 设计模式是前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对某一特定问题的成熟解决方案
- 使用设计模式是为了可重用代码、让代码更容易地被他人理解、保证代码地可靠性
单例设计模式
- 目的 – 让类创建的对象,在系统中只有唯一的一个实例
- 每一次执行
类名()
返回的对象,内存地址是相同的
单例设计模式的应用场景
- 音乐播放对象
- 回收站对象
- 打印机对象
- 都只有唯一的一个存在
__new__
方法
使用类名()
创建对象时,Python
解释器会调用__new__
方法为对象分配空间 __new__
是一个由object
基类提供的内置的静态方法,主要作用有两个
Python
的解释器获得对象的引用后,将引用作为第一个参数,传递给__init__
方法
了解__new__
方法就可以进行改造了
重写__new__
方法的代码十分固定!
重写__new__
方法一定要return super().__new__(cls)
否则,Python
解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
注意:__new__
是一个静态方法,在调用时需要主动传递参数cls
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class MusicPlayer(object): def __new__(cls, *args, **kwargs): # auto call print('Create objects, allocate memory') # 为对象分配空间并返回引用 # return super().__new__(cls)
def __init__(self): print('player init....')
player=MusicPlayer() print(player)
- - - - - - - Create objects, allocate memory None
|
Python中的单例
单例
让类创建的对象,在系统中只有唯一的一个实例,即每次创建对象所返回的引用是一样的
- 定义一个类属性,初始值是
None
,用于记录单例对象的引用
- 重写
__new__
方法
- 如果类属性
is None
,调用父类方法分配空间,记录引用
- 否则,返回这个类属性代表的引用
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class MusicPlayer(object): instance=None def __new__(cls, *args, **kwargs): # auto call # print('Create objects, allocate memory') if MusicPlayer.instance is None: MusicPlayer.instance=super().__new__(cls) return MusicPlayer.instance
def __init__(self): print('player init....')
player1=MusicPlayer() print(player1) player2=MusicPlayer() print(player2)
- - - - - - - - - - - - player init.... <__main__.MusicPlayer object at 0x7f2f98dd69b0> player init.... <__main__.MusicPlayer object at 0x7f2f98dd69b0>
|
可以看到两次创建对象的内存地址是一样的
代码升级
需求
- 使得单例对象在被创建时,只执行一次初始化工作(音乐播放器换歌不需要重启)
解决
- 定义一个类属性
init_flag
初始值为False
标记是否执行过初始化动作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class MusicPlayer(object): instance=None init_flag=False def __new__(cls, *args, **kwargs): # auto call # print('Create objects, allocate memory') if MusicPlayer.instance is None: MusicPlayer.instance=super().__new__(cls) return MusicPlayer.instance
def __init__(self): if MusicPlayer.init_flag == True:return print('player init....') MusicPlayer.init_flag=True
player1=MusicPlayer() print(player1) player2=MusicPlayer() print(player2)
- - - - - - - - - - - - player init.... <__main__.MusicPlayer object at 0x7f5e4abc4a20> <__main__.MusicPlayer object at 0x7f5e4abc4a20>
|
异常
目标
- 概念
- 捕获异常
- 异常的传递
- 自定义异常
概念
程序在运行时,如果Python
解释器遇到一个错误,会停止程序的执行,并且提示一些错误信息,这就是异常
程序停止执行并且提示错误信息这个动作,我们通常称之为:抛出(raise)异常
异常捕获
程序开发时,很难将所有的特殊情况都处理的面面俱到,通过异常捕获可以针对突发事件做集中的处理,从而保证程序的稳定性和健壮性
简单的捕获异常语法
在程序开发中,如果对某些代码的执行不能确定是否正确,可以增加try:
来捕获异常
1 2 3 4 5 6
| try: # try to do pass except: # deal with error pass
|
比如程序设计中常见的多组输入
1 2 3 4 5
| while True: try: a,b=int(input()) print(a+b) except:break
|
根据错误类型捕获异常
在程序执行时,可能会遇到不同类型的异常,并且需要针对不同类型的异常,做出不同的响应,这个时候,就需要捕获错误类型了
1 2 3 4 5 6 7 8 9 10
| try: # 尝试执行的代码 pass except error_1: # 针对错误类型1,对应的代码处理,下面同理 pass except (error_2,error_3): pass except Exception as result: # 捕获未知错误 print('unknown mistake: %s' %result)
|
当Python解释器抛出异常时,最后一行错误信息的第一个单词就是错误类型,即代码中的error
,如ValueError
、ZeroDivisionError
等等
异常捕获完整语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| try: # 尝试执行 pass except error_1: # 错误类型1,对应的处理 pass except (error_2,error_3): pass except Exception as result: print('unknown mistake: %s' result) else: # 没有异常会执行的代码 pass finally: # 无论是否有异常,都会执行的代码 print("this must be execution")
|
异常的传递性
异常的传递 – 当函数/方法执行出现异常,会将异常传递给函数/方法的调用一方
如果传递到主程序,仍然没有异常处理,程序才会被终止
提示:
- 在开发中,可以在主函数中增加异常捕获
- 主函数中调用的其他函数,出现异常都会传递到主函数的异常捕获中
- 只需在主函数中进行异常捕获,保证代码整洁性
主动抛出异常
在开发中,除了代码执行出错Python
解释器会抛出异常外
还可以根据应用程序特有的需求业务主动抛出异常
抛出异常
Python中提供了一个Exception
异常类
在开发时,如果满足特定业务需求时,希望抛出异常,可以:
- 创建一个
Exception
对象
- 使用
raise
关键字抛出异常对象
示例
需求
- 定义
input_password
函数,提示用户输入密码
- 如果用户输入长度<8,抛出异常
- 如果用户输入长度>=8,返回输入的密码
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def input_password(): password=input('please input password: ') if len(password)>=8:return password
print('raise an exception') exp=Exception('the length of password is not enough') raise exp
try: print(input_password()) except Exception as result: print(result)
- - - - - - - - - - - - - please input password: 12345 raise an exception the length of password is not enough
|