欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python 异常处理 与 约束 详解

程序员文章站 2024-03-18 11:30:46
...

错误与异常

'''
程序中难免会出现错误,而错误分为两种

1.语法错误:(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)

2.逻辑错误:(逻辑错误),比如用户输入的不合适等一系列错误

'''

异常的种类

常见的异常

Python 异常处理 与 约束 详解

# 更多异常
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError

异常处理

# 异常处理:当程序遇到问题(异常的)不直接结束程序(崩溃),而越过该错误继续执行 
# 什么时候最容易出异常
# 当你要处理的内容不确定的时候
     # 有用户参与
     # 有外界数据接入 : 从文件中读 从网络上获取

# 当有多行报错的时候是为什么?
def func1():
     name

def func2():
     func1()

def main():
     func2()

main()

# 在嵌套调用的过程中,内部的代码出了问题,外部所有的调用的地方都成为报错追溯信息的一部分

# 怎么解决:
     # 从下往上找 首先找到你写的代码 出错的那一行
     # 看看能不能看出问题
     # 就把报错的最后一行 错误类型和详细提示贴到百度里,结合报错的那一行解决问题

单分支

li = ['login', 'register']
for num, i in enumerate(li, 1):
    print(num, i)

try:
    num = int(input('num >>>'))
except ValueError:  # except处理的异常必须和实际报错的异常是相同的
    print('请输入一个数字')
print(li[num - 1])

多分支

li = ['login', 'register']
for num, i in enumerate(li, 1):
    print(num, i)

try:
    num = int(input('num >>>'))
    print(li[num - 1])
except ValueError:
    # 从上向下报错的代码只要找到一个和报错类型相符的分支就执行这个分支中的代码,然后直接退出分支
    print('请输入一个数字')
except IndexError:
    # 如果找不到能处理和报错类型相同的分支,会一直往下走,最后还是没有找到就会报错
    print('只能输入1或2')

多分支合并

li = ['login', 'register']
for num, i in enumerate(li, 1):
    print(num, i)

try:
    num = int(input('num >>>'))
    print(li[num - 1])
except (ValueError, IndexError):  # 多个异常写成元组形式
    print('您输入的内容不合法')

万能异常

def back():
    print('back')
    [][1]


def show():
    print('show')
    1 / 0


def main():
    li = [('购物', buy), ('退货', back), ('查看订单', show)]  # 里面的变量也是函数名
    while True:
        for num, i in enumerate(li, 1):
            print(num, i[0])
        num = int(input('num >>>'))
        print(li[num - 1])
        try:
            func = li[num - 1][1]
            func()
        except Exception:
            print('用户在选择了%s操作之后发生了不可知的异常' % li[num - 1][0])


main()

万能异常 如何处理

# as 语法
# 能够将具体错误信息打印出来


def buy():
    print('buy')
    name


def back():
    print('back')
    [][1]


def show():
    print('show')
    1 / 0


def main():
    l = [('购物', buy), ('退货', back), ('查看订单', show)]
    while True:
        for num, i in enumerate(l, 1):
            print(num, i[0])
        num = int(input('num >>>'))
        print(l[num - 1])
        try:
            func = l[num - 1][1]
            func()
        except Exception as e:  # e 的名字可以随便取
            print(e)
            # print(e.args,e.__traceback__.tb_lineno,e.__traceback__.tb_frame)
        print('用户在选择了%s操作之后发生了不可知的异常' % l[num - 1][0])


main()

多分支+万能异常

def buy():
    print('buy')
    name


def back():
    print('back')
    [][1]


def show():
    print('show')
    1 / 0


def main():
    l = [('购物', buy), ('退货', back), ('查看订单', show)]
    while True:
        for num, i in enumerate(l, 1):
            print(num, i[0])
        try:
            num = int(input('num >>>'))
            print(l[num - 1])
            func = l[num - 1][1]
            func()
        except (ValueError, IndexError):
            print('您输入的内容不合法')
        except Exception as e:
            print(e)
            # print(e.args,e.__traceback__.tb_lineno,e.__traceback__.tb_frame)
            print('用户在选择了%s操作之后发生了不可知的异常' % l[num - 1][0])


main()
# try...except 总结:
try:
    pass
except (ValueError, IndexError):
    print('针对性的处理')
except Exception as e:
    print(e)
    print('通用性的处理')

else分支

try:
    print('aaa')  # 给某某某发邮件
    # name
    # [][1]
    # 1/0
except NameError:  # 网络不稳定,邮箱地址错误
    print('name error')
except IndexError:
    print('index error')
except Exception as e:
    print('Exception')
else:  # 当try中的代码不发生异常的时候 走else分支  如果发送成功了 进行一些处理
    print('else')

finally分支

# return 和 finally
def func():
    f = open('file')
    try:
        while True:
            for line in f:
                if line.startswith('a'):
                    # f.close 通常可以在读取到文件后,关闭文件,但是前面也可能出现问题
                    return line
    except:
        print('异常处理')
    finally:  # 即使return也会先执行fianlly中的代码
        f.close()


# 这里的关闭文件,无论代码发没发生异常,都会执行,满足关闭文件的需求

# 直接try和finally结合
try:
    f = open('www', 'w')
    f.read()
finally:  # 即使遇到报错,程序结束,也会先执行finally中的代码,然后再结束程序
    f.close()
    print('文件已经关闭了')

# finally用来回收一些操作系统的资源 : 数据库连接 打开的文件句柄 网络连接

# 异常处理的几种情况
'''
try ... except
try ... except ... else
try ... finally
try ... except ... finally
try ... except ... else ... finally
'''

# 总结
'''
try...except应该尽量少用,因为它本身就是你附加给你的程序的一种异常处理的逻辑,与你的主要的工作是没有关系的

这种东西加的多了,会导致你的代码可读性变差,只有在有些异常无法预知的情况下,才应该加上try...except,

其他的逻辑错误应该尽量修正
'''

断言

# 断言 - 语法
assert 1==2  # 只能接受一个布尔值False 报错
print(123456)

assert 1==1 # 只能接受一个布尔值True 执行
print(123456)

# 相当于:
if 1 == int(input()):
	pass
else:
	raise AssertionError


# 常处理的忠告,在最外层的异常处理应该在所有的开发结束之后才放
main()
     sdhjlkghl
try:
     main()
except Exception as e:
     # 把e报错写到文件里
     

自定义异常类

import os


class ExistsError(Exception):  # 自定义异常,继承基类Exception
    pass


class KeyInvalidError(Exception):
    pass


def new_func(path, prev):
    """
    去path路径的文件中,找到前缀为prev的一行数据,获取数据并返回给调用者。
         1000,成功
         1001,文件不存在
         1002,关键字为空
         1003,未知错误
         ...
    :return:
    """
    response = {'code': 1000, 'data': None}
    try:  # 这里开始写主要业务逻辑
        if not os.path.exists(path):
            raise ExistsError()

        if not prev:
            raise KeyInvalidError()
        pass

    except ExistsError as e:
        response['code'] = 1001
        response['data'] = '文件不存在'
    except KeyInvalidError as e:
        response['code'] = 1002
        response['data'] = '关键字为空'
    except Exception as e:
        response['code'] = 1003
        response['data'] = '未知错误'
    return response
# 自定义异常的实质
class MyException(Exception):  # 基础 基类 Exception
    def __init__(self, code, msg):
        self.code = code
        self.msg = msg


try:
    raise MyException(1000, '操作异常')  # raise相当于一次对象实例化

except MyException as obj(e):  # as 后就是 对象名
    print(obj.code, obj.msg)

约束

第一种:抛出异常


class BaseMessage(object):
    def send(self, x1):  # 参数也必须一致
        """
        必须继承BaseMessage,然后其中必须编写send方法。用于完成具体业务逻辑。
        """
        raise NotImplementedError(".send() 必须被重写.")
        # raise NotImplementedError(".send()must be overridden.")


class Email(BaseMessage):
    def send(self, x1):
        """
        必须继承BaseMessage,然后其中必须编写send方法。用于完成具体业务逻辑。
        """
        pass


obj = Email()
obj.send(1)

第二种不常用的约束(抽象类,抽象方法)

Python 异常处理 与 约束 详解

from abc import ABCMeta, abstractmethod


class Base(metaclass=ABCMeta):  # 抽象类

    def f1(self):
        print(123)

    @abstractmethod
    def f2(self):  # 抽象方法
        pass


class Foo(Base):
    def f2(self):
        print(666)


obj = Foo()
obj.f1()

总结

"""
     1. 什么是接口以及作用?
          接口时一种数据类型,主要用于约束派生类中必须实现指定的方法。
          Python中不存在,Java和C# 中是存在的。
     2. Python中使用过什么来约束呢?
          抽象类+抽象方法,编写上麻烦。
          人为主动抛出异常 

     3. 约束时,抛出的异常是否可以用其他的?
          不专业:raise Exception(".send() 必须被重写.")
          专业:raise NotImplementedError(".send() 必须被重写.")
"""

应用场景

# 多个类,内部都必须有某些方法时,需要使用基类+异常进行约束。
# 如:学员管理系统

class IBase:
    def login(self):
        raise NotImplementedError(".send() 必须被重写.")


class Student:
    def login(self):
        pass

    def score(self):
        pass


class Teacher:
    def login(self):
        pass

    def exam(self):
        pass


class Manager(object):
    def login(self):
        pass