python进阶(10)——单例/异常

单例

设计模式:前人留下的对某一特定问题的成熟的解决方案(套路)

单例设计模式:类创建的对象,在系统中只有唯一一个实例,每一次执行类名()返回的对象,内存地址是相同的

__new__方法:

使用类名()创建对象时,python解释器执行两步:

1首先调用__new__内置方法为对象分配空间,返回对象的引用(地址)

2调用__init__内置方法进行对象初始化

class MusicPlayer(object):
    pass


# 创建多个对象
player1 = MusicPlayer()
print(player1)

player2 = MusicPlayer()
print(player2)
<__main__.MusicPlayer object at 0x10126a4a8>
<__main__.MusicPlayer object at 0x10126a470>

输出的两个内存地址不一样,说明player1和player2是两个完全不同的对象

单例设计模式的目的就是无论创建多少次,对象的引用(地址)是相同的,怎么解决?

定义一个类属性instance,初始值是None,用于记录对象的引用(初始时没有值)

class MusicPlayer(object):

    # 定义类属性,记录第一个被创建对象的引用
    instance = None

    def __new__(cls, *args, **kwargs):

        # 1 判断类属性是否是空对象
        if cls.instance is None:
            # 2 调用父类的方法,为第一个对象分配空间
            cls.instance = super().__new__(cls)

        # 3 返回类属性保存的对象引用
        return cls.instance


# 创建多个对象
player1 = MusicPlayer()
print(player1)

player2 = MusicPlayer()
print(player2)
<__main__.MusicPlayer object at 0x1049c5438>
<__main__.MusicPlayer object at 0x1049c5438>

如果想要初始化动作只执行一次?

定义类属性,判断是否执行过初始化

class MusicPlayer(object):

    # 定义类属性,记录第一个被创建对象的引用
    instance = None

    # 定义类属性,记录是否执行过初始化动作
    init_flag = False

    def __new__(cls, *args, **kwargs):

        # 1 判断类属性是否是空对象
        if cls.instance is None:
            # 2 调用父类的方法,为第一个对象分配空间
            cls.instance = super().__new__(cls)

        # 3 返回类属性保存的对象引用
        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)

异常

程序在运行时,遇到错误停止运行并提示一些错误信息

通过异常捕获,保证程序的健壮性

在程序的开发中,如果对某些代码的执行不确定是否正确,可以增加try来捕获异常

格式:

try:
尝试执行的代码
except:
出现错误的处理
try:

    num = int(input("请输入一个整数:"))
except:
    
    print("请输入正确的整数")

print("-" * 50)
请输入一个整数:eee
请输入正确的整数
--------------------------------------------------

异常类型捕获演练:

输入一个非零整数,进行除以8的操作,

错误类型:

try:

    num = int(input("请输入一个整数:"))
    result = 8 / num
    print(result)

except ZeroDivisionError:
    print("除0错误")

except ValueError:
    print("请输入正确的整数")

以上捕获的错误类型都是已知的错误,如果想对未知的错误进行捕获?

可以再增加一个except

try:

    num = int(input("请输入一个整数:"))
    result = 8 / num
    print(result)

except ZeroDivisionError:
    print("除0错误")

#假设输入非整数时为未知错误
except Exception as result:
    print("未知错误%s" % result)
请输入一个整数:a
未知错误invalid literal for int() with base 10: 'a'

异常捕获完整语法

try:

    num = int(input("请输入一个整数:"))
    result = 8 / num
    print(result)

except ZeroDivisionError:
    print("除0错误")

except ValueError:
        print("请输入正确的整数")

except Exception as result:
    print("未知错误%s" % result)

else:
    print("尝试成功")

finally:
    print("无论是否出现错误都会执行的代码")

异常的传递:

把异常传递给函数或方法的调用方,程序不会被立刻终止

例:定义函数demo1()提示用户输入一个整数并返回;定义函数demo2()调用demo1();在主程序中使用demo2()

def demo1():
    return int(input("输入整数:"))


def demo2():
    return demo1()


# 利用异常的传递性,在主程序捕获异常
try:
    print(demo2())
except Exception as result:
    print("位置错误 %s" % result)

运行结果

输入整数:a
位置错误 invalid literal for int() with base 10: 'a'

注:

在开发中,在主函数中添加异常捕获

在主函数中调用的其他函数,只要出现异常,都会传递到主函数的异常捕获中

这样就不需要在代码中,增加大量的异常捕获,能够保证代码的整洁性

在实际开发中,除了代码出错需要抛出异常,还可以根据应用程序特有的业务需求主动抛出异常:

1.创建exception异常对象

2.使用raise关键字抛出异常对象

例,提示用户输入密码,如果长度少于8,抛出异常

def input_password():

    # 1.输入密码
    pwd = input("请输入密码")

    # 2.判断长度>=8,返回用户输入的密码
    if len(pwd) >= 8:
        return

    # 3.如果<8主动抛出异常
    print("主动抛出异常")
    ex = Exception("密码长度不够")
    raise ex

try:
    print(input_password())
except Exception as result:
    print(result)

猜你喜欢

转载自blog.csdn.net/weixin_40725491/article/details/83866180