python之单例设计模式、异常

一、单例设计模式

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__方法改造之后,每次都会得到一次被创建对象的引用,初始化方法会被再次调用

现在的需求是:让初始化方法只执行一次

解决办法:

  1. 义一个类属性init_flag标记是否执行过初始化动作,初始值为False
  2. 在__init__方法中,判断init_flag,如果False就会执行初始化动作
  3. 然后将init_flag设置为True
  4. 这样,再次自动调用__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)

猜你喜欢

转载自blog.csdn.net/qq_38484607/article/details/82709237