zoukankan      html  css  js  c++  java
  • 异常处理和约束

    主要内容:

    • 1. 异常处理
    • 2. 类的约束
    • 3. MD5加密
    • 4. 日志

    1. 异常处理

        异常就是程序在运行过程中产生的错误

     (1)异常处理方案一:

    def calculate(a,b):
        return a/b
    try:
        ret = calculate(10,0)
        print(ret)
    except Exception as e:
        print("除数不能是0")        # 除数不能是0 

      try...except的含义:

    •  尝试着运行xxxxx代码. 出现了错误. 就执行行except后面的代码.
    •  在这个过程中,当代码出现错误的时候,系统会产生⼀个异常对象,然后这个异常会向外抛,被except拦截,并把接收到的异常对象赋值给e
    •  这里的e就是异常对象,这里的Exception是所有异常的基类, 也就是异常的跟,即所有的错误都是Exception的子类对象.

    然而:

          用Exception表示所有的错误,太笼统了,所有的错误都会被认为是Exception. 当程序中出现多种错误的时候, 就不好分类了, 最好是出什么异常就用什么来处理,更加合理了,所以在try...execpt语句中会写更多的except.

    try:    
        print("各种操作....") 
    except ZeroDivisionError as e:    
        print("除数不能是0") 
    except FileNotFoundError as e:    
        print("文件不存在") 
    except Exception as e:    
        print("其他错误")

    此时. 程序运行过程中,如果出现了ZeroDivisionError就会被第⼀个except捕获, 如果出现了FileNotFountError就会被第⼆个except捕获. 如果都不是这两个异常. 那就会被最后的 Exception捕获. 总之最后的Exception就是我们异常处理理的最后一个守门员. 

    完整的异常处理写法(语法): 

    try:
        '''操作'''
    except Exception as e:
    '''异常的父类,可以捕获所有的异常'''
    else:
    '''保护不抛出异常的代码, 当try中无异常的时候执行'''
    finally:
    '''最后总是要执行我'''

    解读:程序先执行操作, 然后如果出错了会走except中的代码,如果不出错, 执行else中的代码,不论出不出错. 最后都要执行finally中的语句,一般try...except就够用了,顶多加上finally,finally⼀般用来作为收尾工作.

    (2)异常处理方案二:

    情境: 执行代码的过程中如果出现了一些条件上的不对等,根本不符合我的代码逻辑. 比如.传递参数时,要求传递个数字,如果用户传递一个字符串 ,此时没办法处理,那如何通知你呢?两个方案的处理方式    

    • 方案一. 直接返回,我不管你还不行么? 
    • 方案二. 抛出一个异常,明确告诉你错误   (代码中如果出现了类似的问题直接抛一个错误出去)
    def add(a,b):
        """传递两个整数,
        我帮你计算两个数的和
        :param :param a:
        :param :param b:
        :return :return:
        """
        if not type(a) == int and not type(b) == int:    #当程序运行到这句话时,整个函数调用就会被中断,并外抛一个异常.
            raise Exception("不是整数,不能进行计算")
        return a + b
    #如果调用方不处理异常,产生的错误就会就绪向外抛,最后就抛了用户
    # add("时间","空间")
    
    # 如果调用方处理的了异常,那么错误就不会丢给用户,程序也能正常运行
    try:
        add("胡辣汤","肉夹馍")
    except Exception as e:
        print("报错了,自己处理吧")

    (3) 自定义的异常

    • 当代码中出现了了⼀个无法用现有的异常来解决问题时,我们需要自定义异常
    • 自定义异常: 当这个类继承了Exception类,那它就成为了一个异常类.
    class GenderError(Exception):
        pass
    class Person:
        def __init__(self,name,gender):
            self.name = name
            self.gender = gender
    
    def nan_zaotang(person):
        if person.gender != "":
            raise GenderError("性别不对,这里是男澡堂")
    p1 = Person("alex","")
    p2 = Person("eggon","")
    
    # nan_zaotang(p1)
    # nan_zaotang(p2)              # 报错,会抛出一个异常  GenderError
    
    #处理异常
    try:
        nan_zaotang(p1)
        nan_zaotang(p2)
    except GenderError as e:
        print(e)              #性别不对,这里是男澡堂
    except Exception as e:
        print("反正错了")

    但是, 如果是真的报错l. 我们在调试的时候, 最好是能看到错误源自于哪里? 这时需要引入另⼀个模块traceback,这个模块可以获取到我们每个方法的调用信息,又被成为堆栈信息.

    import traceback
    class GenderError(Exception):
        pass
    class Person:
        def __init__(self,name,gender):
            self.name = name
            self.gender = gender
    
    def nan_zaotang(person):
        if person.gender != "":
            raise GenderError("性别不对,这里是男澡堂")
    p1 = Person("alex","")
    p2 = Person("eggon","")
    
    # nan_zaotang(p1)
    # nan_zaotang(p2)              # 报错,会抛出一个异常  GenderError
    
    #处理异常
    try:
        nan_zaotang(p1)
        nan_zaotang(p2)
    except GenderError as e:
        val = traceback.format_exc()
        print(e)              #性别不对,这里是男澡堂
        print(val)
    except Exception as e:
        print("反正错了")
    
    #性别不对,这里是男澡堂
    # Traceback (most recent call last):
    #   File "E:/Python_workspace/day020/020整理.py", line 83, in <module>
    #     nan_zaotang(p2)
    #   File "E:/Python_workspace/day020/020整理.py", line 73, in nan_zaotang
    #     raise GenderError("性别不对,这里是男澡堂")
    # GenderError: 性别不对,这里是男澡堂

     当测试代码的时候把堆栈信息打印出来,但是当到了线上的生产环境的时候把这个堆栈去掉即可 

    2. 类的约束

    (1)第一套方案

    • 提取父类. 然后在父类中定义好方法. 在这个方法中什么都不用干,抛⼀个异常就可以了. 这样所有的子类都必须重写这个方法,否则. 访问的时候就会报错.
    • 使用元类来描述父类. 在元类中给出⼀个抽象方法,这样子类就不得不给出抽象方法的具体实现,也可以起到约束的效果.
    class Base:
        def login(self):
            raise Exception("你没有实现login方法()")
    class Normal(Base):
        def login(self):
            pass
    class Member(Base):
        def denglu(self):
            pass
    class Admin(Base):
        def login(self):
            pass
    
    def login(obj):
        print("准备验证码......")
        obj.login()
        print("进入主页........")
    
    n = Normal()
    m = Member()
    a = Admin()
    login(n)
    login(m)                         #报错
    login(a)

       在执行到login(m)的时候程序会报错,原因是, 此时访问的login()是父类中的方法,但是父类中的方法会抛出⼀个异常, 所以报错. 这样程序员就不得不写login方法了,从而对子类进行了相应的约束.

    在本示例中,要注意,我们抛出的是Exception异常,而Exception是所有异常的根. 我们无法通过这个异常来判断出程序是因为什么报的错,所以. 最好是换⼀个比较专业的错误信息,最好 是换成NotImplementError. 其含义是. "没有实现的错误".这样可以一目了然的知道是什么错了

    (2)第二套方案:写抽象类和抽象方法

     在python中编写一个抽象类比较麻烦,需要引入abc模块中的ABCMeta和 abstractmethod这两个内容.

    from abc import ABCMeta, abstractmethod
    class Animal(metaclass=ABCMeta): # 在父类中写出metaclass= xxx  抽象类, 类中存在抽象方法, 类一定是抽象类
    
        @abstractmethod # 抽象方法
        def chi(self): # 抽象的概念.
            pass
        def haha(self):
            print("娃哈哈")
    
    class Cat(Animal): # 子类必须实现父类中的抽象方法.
        def chi(self):  # 具体的实现
            print("猫爱吃鱼")
    # a = Animal()    #抽象类不能创建对象
    c = Cat()
    c.chi()

    这时来解决开始的问题

    from abc import ABCMeta,abstractmethod
    class Base(metaclass=ABCMeta):
        @abstractmethod
        def login(self):pass
    
    # 张三
    class Normal(Base):
        def login(self):
            print("普通人登陆")
    # 李四
    class Member(Base):
        def login(self):
            print("吧务登陆")
    # 王五
    class Admin(Base):
        def login(self):
            print("管理员登陆")
    def login(obj):
        print("产生验证码")
        obj.login() # 标准在这里.  必须由login
        print("进入主页")
    
    # 场景
    n = Normal()
    m = Member()
    a = Admin()
    login(n)
    login(m)
    login(a)

    总结: 

    约束. 其实就是父类对子类进行约束,子类必须要写xxx方法. 在python中约束的方式方法有两种:

    • 1. 使用抽象类和抽象方法, 由于该方案来源是java和c#. 所以使用频率还是很少的
    • 2. 使用人为抛出异常的方案.  并且尽量量抛出的是NotImplementError,这样比较专业,而且错误比较明确(推荐)

    3. MD5加密

    MD5是⼀种不可逆的加密算法,

     它是可靠的,并且安全的,在python中我们不需要手写这⼀套算法,只需要引入⼀个叫hashlib的模块就能搞定MD5的加密工作 

    import hashlib
    # 1. 创建一个MD5对象
    obj = hashlib.md5(b"flkjsdalkfjklasdjfklasjkflasdjklfasdjflkadsj") # 加盐
    
    # 2. 把要加密的内容给md5
    obj.update("alex".encode("utf-8")) # 必须是字节
    
    # 3. 获取密文
    val = obj.hexdigest()   # 534b44a19bf18d20b71ecc4eb77c572f aa7aa5ec13222b27f76a094207c5ac75
    print(val)
    
    def my_md5(val):
        obj = hashlib.md5(b"flkjsdalkfjklasdjfklasjkflasdjklfasdjflkadsj")
        obj.update(val.encode("utf-8"))
        val = obj.hexdigest()
        return val
    
    # 注册的时候. 用md5进行加密. 存储的是加密后的密文
    username = input("请输入用户名")
    password = input("请输入密码")
    # cun = my_md5(password)
    # print(cun)                                 # alex 26adff81aa6778d26999b95ddc0e50b2
    if username == "alex" and my_md5(password) == "26adff81aa6778d26999b95ddc0e50b2":
        print("登录成功")
    else:
        print("登录失败")

    4. 日志

    在python中创建日志系统

    • 导入logging模块.
    • 简单配置⼀一下logging
    • 出现异常的时候(except). 向日志里写错误信息.

    (1)单日志文件的处理

    import logging
    logging.basicConfig(filename='app.log',
                        format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S',
                        level=0)    # level 设置级别. 当你的信息的级别>=level的时候才会写入日志文件, 默认30
    # CRITICAL = 50
    # FATAL = CRITICAL
    # ERROR = 40
    # WARNING = 30
    # WARN = WARNING
    # INFO = 20
    # DEBUG = 10
    # NOTSET = 0
    # 写日志
    logging.critical("我是critical")
    logging.error("我是error")
    logging.warning("我是警告")
    logging.info("我是基本信息")
    logging.debug("我是调试")
    logging.log(2, "我是自定义")

    检测下:

    import logging
    logging.basicConfig(filename='app.log',
                        format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S',
                        level=0)    # level 设置级别. 当你的信息的级别>=level的时候才会写入日志文件, 默认30
    # CRITICAL = 50
    # FATAL = CRITICAL
    # ERROR = 40
    # WARNING = 30
    # WARN = WARNING
    # INFO = 20
    # DEBUG = 10
    # NOTSET = 0
    # 写日志
    # logging.critical("我是critical")
    # logging.error("我是error")
    # logging.warning("我是警告")
    # logging.info("我是基本信息")
    # logging.debug("我是调试")
    # logging.log(2, "我是自定义")
    
    import traceback
    for i in range(30):
        try:
            if i%3==0:
                raise FileNotFoundError()
            if i%3==1:
                raise StopIteration()
            if i%3==2:
                raise KeyError()
        except FileNotFoundError as e:
            val = traceback.format_exc()
            logging.error(val)
        except StopIteration as e:
            val = traceback.format_exc()
            logging.error(val)
        except KeyError as e:
            val = traceback.format_exc()
            logging.error(val)
        except Exception as e:
            val = traceback.format_exc()
            logging.error(val)

    (2)多日志文件的处理

    # 创建⼀个操作⽇志的对象logger(依赖FileHandler)
    file_handler = logging.FileHandler('l1.log', 'a', encoding='utf-8')
    # 设置日志文件内容的格式
    file_handler.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s"))
    logger1 = logging.Logger('A', level=40)
    logger1.addHandler(file_handler)
    # 记录日志
    logger1.error('我是A系统')
    
    
    
    # 再创建⼀个操作⽇志的对象logger(依赖FileHandler)
    file_handler2 = logging.FileHandler('l2.log', 'a', encoding='utf-8')
    file_handler2.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s -%(levelname)s -%(module)s: %(message)s"))
    logger2 = logging.Logger('B', level=40)
    logger2.addHandler(file_handler2)
    # 记录日志
    logger2.error('我是B系统')
  • 相关阅读:
    POJ 3660 Cow Contest (floyd求联通关系)
    POJ 3660 Cow Contest (最短路dijkstra)
    POJ 1860 Currency Exchange (bellman-ford判负环)
    POJ 3268 Silver Cow Party (最短路dijkstra)
    POJ 1679 The Unique MST (最小生成树)
    POJ 3026 Borg Maze (最小生成树)
    HDU 4891 The Great Pan (模拟)
    HDU 4950 Monster (水题)
    URAL 2040 Palindromes and Super Abilities 2 (回文自动机)
    URAL 2037 Richness of binary words (回文子串,找规律)
  • 原文地址:https://www.cnblogs.com/wcx666/p/9725167.html
Copyright © 2011-2022 走看看