一、单例设计模式
1、设计模式
设计模式是前人的总结和经验的提炼,通常被人们广为流传
2、单例
由类创建的对象,在系统中有唯一的实例
3、创建对象的步骤
(1)为对象分配空间:__new__()
创建对象的时候,python解释器首先会调用__new__方法为对象分配空间,__new__是一个有object基类提供的内置的静态方法,主要有两个作用:
- 在内存中为对象分配空间
- 返回对象的引用
(2)对象初始化:__init__()
Python解释器获得对象的引用后,将引用的第一个参数,传递给__init__方法
4、实例分析
class MusicPlayer(object):
def __new__(cls, *args, **kwargs):
#第一个参数cls:哪一个类调用就传递哪一个类
#第二个参数*args:是一个多值元组参数
#第三个参数**kwargs:是一个多值字典参数
#1.创建对象时,new方法会被自动调用
print '创建对象,分配空间'#重写了父类
#2.为对象分配空间
#__new__方法是一个静态方法,在调用时,第一个参数是cls
instance = object.__new__(cls)
#3.返回对象的引用
return instance
def __init__(self):
print '初始化播放器'
#创建播放器对象
player1 =MusicPlayer()
print player1
player2 =MusicPlayer()
print player2
二、单例的高阶用法
1、重写__new__方法:继承自父亲类方法,返回父亲类方法是调用__new__方法的结果
应该注意的是重写__new__方法一定要return object.__new__(cls):
否则Python的解释器得不到分配空间的对象的引用,就不会调用对象的初始化方法
- 定义一个类属性,初始值为None,用于记录单例对象的引用(当一个类定义完成运行程序的时候,内存中由这个类创建的对象吗?) 并没有只有我们需要调用创建对象的方法,内存中才会有第一个对象
- 重写__new__方法
- 如果类属性is None,调用父类方法分配空间,并在类属性中记录结果
- 返回类属性中记录的对象的引用
实例:
class MusicPlayer(object):
instance=None
def __new__(cls, *args, **kwargs):
#第一个参数cls:哪一个类调用就传递哪一个类
#第二个参数*args:是一个多值元组参数
#第三个参数**kwargs:是一个多值字典参数
# 判断类属性是否为空(如果是空对象,说明第一个对象还没被创建)
if cls.instance is None:
# 调用父类的方法,为第一个对象分配空间
cls.instance=object.__new__(cls)
#返回类属性保存的对象引用
return cls.instance
player1 =MusicPlayer()
print player1
player2 =MusicPlayer()
print player2
2、调用一次内置方法
在每次使用 类名() 创建对象的时候,Python的解释器都会自动调用两个方法
- __new__ 分配空间
- __init__ 对象初始化
在之前实例中,__new__方法改造之后,每次都会得到一次被创建对象的引用,初始化方法会被再次调用
现在的需求是:让初始化方法只执行一次
解决办法:
- 定义一个类属性init_flag标记是否执行过初始化动作,初始值为False
- 在__init__方法中,判断init_flag,如果False就会执行初始化动作
- 然后将init_flag设置为True
- 这样,再次自动调用__init__方法时,初始化动作就不会再次被执行了
实例:
class MusicPlayer(object):
# 记录第一个被创建对象的应用
instance = None
init_flag = False
def __new__(cls, *args, **kwargs):
# 判断类属性是否为空(如果是空对象,说明第一个对象还没被创建)
if cls.instance is None:
# 调用父类的方法,为第一个对象分配空间
cls.instance = object.__new__(cls)
# 返回类属性保存的对象引用
return cls.instance
def __init__(self):
# 1.判断是否执行过初始化方法
if MusicPlayer.init_flag:
return
# 2.如果没有执行,执行初始化动作
print '初始化播放器'
# 3.修改类属性的标记
MusicPlayer.init_flag = True
# 创建多个对象
player1 = MusicPlayer()
print player1
player2 = MusicPlayer()
print player2
三、异常
1、捕获异常
(1)什么时候会出现异常?
程序在运行的时候,如果python解释器遇到一个错误,会停止程序的执行,并且提示一些错误的信息,这就是异常
那么在程序开发时,很难将所有的特殊情况都处理,通常异常捕获可以针对突发事件做集中处理,从而保证程序的健壮性和稳定性
(2)如何捕捉异常?
在程序开发中,如果对某些代码的执行不能确定(程序语法完全正确),可以增加try来捕获异常
try:
尝试执行的代码
except:
出现错误的处理
2、异常已知的情况
根据错误类型来捕获异常
执行步骤:
try:
尝试执行的代码
except 错误类型1:
针对错误类型1,对应的代码处理
except 错误类型2:
针对错误类型2,对应的代码处理
...
需求:
- 提示用户输入一个整数
- 使用8除以用户输入的整数并输出
try:
#提示用户输入一个整数
num = int(raw_input('输入一个整数:'))
#使用8除以整数并输出
result = 8/num
print result
except ZeroDivisionError:
print '0不能做除数'
except ValueError:
print '输入的值不是数字'
print '*' *50
当你不清楚错误类型时 : except Exception as result:
try:
#提示用户输入一个整数
num = int(raw_input('输入一个整数:'))
#使用8除以整数并输出
result = 8/num
print result
# except ZeroDivisionError:
# print '0不能做除数'
except ValueError:
print '输入的值不是数字'
except Exception as result:
print '未知错误%s'%result
finally:
#无论是否有异常,都会执行的代码
print '无论是否有异常,都会执行的代码'
3、主动抛出异常
需求:提示用户输入密码,如果长度小于8,就抛出异常
def input_passwd():
#1.提示用户数入密码
pwd = raw_input('请输入密码:')
#2.判断密码的长度 >=8,返回用户的密码
if len(pwd)>=8:
return pwd
#3.如果<8主动抛出异常
print '主动抛出异常'
#1.创建异常对象
ex =Exception('密码长度不够')
#2.主动抛出异常
raise ex
#注意:只抛出异常而不捕获异常,代码会出错
try:
print input_passwd()
except Exception as result:
print result
4、异常的传递
当函数/方法的执行出现异常,会将异常传递给函数/方法调用的一方
def demo1():
return int(raw_input('请输入整数:'))
def demo2():
return demo1()
#函数的错误:一级一级的去找,最终会将异常传递到主程序里
#print demo2()
try:
print demo2()
except Exception as result:
print '未知错误%s'%result
5、断言
可以理解为提前预言,让人更好的知道错误原因
def func(num,div):
assert (div!=0),'div不能为0'
return num/div
print func(10,0)