zoukankan      html  css  js  c++  java
  • python D19 约束、日志

    # 今日主要内容:
    # 1. 约束(1. 抛出异常, 2. 写抽象类)(难点, 重点)
    # 1. 抛出异常; NotImplementedError
    # 2. 抽象类
    # from abc import ABCMeta, abstractmethod
    #
    # class Base(metaclass = ABCMeta): 抽象类
    # @abstractmethod
    # def 方法(self):pass
    #
    # class Foo(Base): 子类必须重写父类中的抽象方法
    # def 方法(self):
    # pass
    # 一个类包含类抽象方法. 这个类一定是抽象类
    # 抽象类中可以有正常的方法
    #
    # 抽象类中如果有抽象方法. 这个类将不能创建对象
    #
    # 接口: 类中都是抽象方法
    #
    # 2. 异常处理
    # try:
    #
    # except Error as e:
    #
    # except....
    #
    # else:
    #
    # finally:
    # 收尾
    #
    # import traceback
    # try:
    # # 尝试执行的代码
    # except Exception as e:
    # # 除了错之后要做什么
    # traceback.format_exc() # 获取堆栈信息(错误信息)
    #
    # 3. 日志处理
    # logging
    #
    # 错误等级
    # critical
    # error(最多)
    # wraning
    # info
    # debug

    # 一、类的约束
    # ⾸先, 你要清楚. 约束是对类的约束. 比如. 现在. 你是⼀个项⽬经理. 然后呢. 你给⼿下
    # 的⼈分活. 张三, 你处理⼀下普通⽤户登录, 李四, 你处理⼀下会员登录, 王五, 你处理⼀下管
    # 理员登录. 那这个时候呢. 他们就开始分别取写他们的功能了. 但是呢. 你要知道, 程序员不⼀
    # 定会有那么好的默契. 很有可能三个⼈会写完全三个不同的⽅法. 就比如这样:
    # class Normal: # 张三, 普通⼈登录
    # def login(self):
    # pass
    # class Member: # 李四, 会员登录
    # def denglu(self):
    # pass
    # class Admin: # 王五, 管理员登录
    # def login(self):
    # pass

    # 然后呢, 他们把这样的代码交给你了. 你看了⼀眼. 张三和王五还算OK 这个李四写的是
    # 什么⿁? denglu.......难受不. 但是好⽍能⽤. 还能凑合. 但是这时. 你这边要使⽤了. 问题就来了.
    # 项⽬经理写的总⼊⼝

    # def login(obj):
    # print("准备验证码.......")
    # obj.login()
    # print("进⼊主⻚.......")

    # 对于张三和王五的代码. 没有问题. 但是李四的. 你是不是调⽤不了. 那如何避免这样的
    # 问题呢? 我们要约束程序的结构. 也就是说. 在分配任务之前就应该把功能定义好. 然后分别
    # 交给底下的程序员来完成相应的功能.
    # 在python中有两种办法来解决这样的问题
    # 1. 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异
    # 常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错
    #
    # 2. 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象
    # ⽅法的具体实现. 也可以起到约束的效果.

    # ⾸先, 我们先看第⼀种解决⽅案: ⾸先, 提取⼀个⽗类. 在⽗类中给出⼀个⽅法. 并且在⽅
    # 法中不给出任何代码. 直接抛异常.
    # 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. 其含义是. "没有实现的错误". 这样程序员或者项⽬经理可以⼀⽬
    # 了然的知道是什么错了. 就好比. 你犯错了. 我就告诉你犯错了. 你也不知道哪⾥错了. 这时我
    # 告诉你, 你xxx错了. 你改也好改不是?

    # 第⼆套⽅案: 写抽象类和抽象⽅法. 这种⽅案相对来说比上⼀个⿇烦⼀些. 需要给⼤家先
    # 引入⼀个抽象的概念. 什么是抽象呢? 想⼀下. 动物的吃. 你怎么描述? ⼀个动物到底应该怎
    # 么吃? 是不是描述不清楚. 这⾥动物的吃就是⼀个抽象的概念. 只是⼀个动作的概念. 没有具
    # 体实现. 这种就是抽象的动作. 换句话说. 我们如果写⼀个⽅法. 不知道⽅法的内部应该到底
    # 写什么. 那这个⽅法其实就应该是⼀个抽象的⽅法. 如果⼀个类中包含抽象⽅法. 那么这个类
    # ⼀定是⼀个抽象类. 抽象类是不能有实例的. 比如. 你看看⼀些抽象派的画作. 在现实中是不
    # 存在的. 也就⽆法建立实例对象与之相对应. 所以抽象类⽆法创建对象. 创建对象的时候会报
    # 错.
    # 在python中编写⼀个抽象类比较⿇烦. 需要引入abc模块中的ABCMeta和
    # abstractmethod这两个内容. 来我们看⼀个例⼦.

    # from abc import ABCMeta, abstractmethod
    # # 类中包含了抽象⽅法. 那此时这个类就是个抽象类. 注意: 抽象类可以有普通⽅法(抽象类不能创建对象)
    # class IGame(metaclass=ABCMeta):
    # # ⼀个游戏到底怎么玩⼉? 你能形容? 流程能⼀样么?
    # @abstractmethod
    # def play(self):
    # pass
    # def turn_off(self):
    # print("破B游戏不玩了, 脱坑了")
    # class DNFGame(IGame):
    # # ⼦类必须实现⽗类中的抽象⽅法. 否则⼦类也是抽象类
    # def play(self):
    # print("dnf的玩⼉法")
    # # g = IGame() # 抽象类不能创建对象
    # dg = DNFGame()
    # dg.play()

    # 通过代码我们能发现. 这⾥的IGame对DNFGame进⾏了约束. 换句话说. ⽗类对⼦类进⾏了约束.
    # 接下来. 继续解决我们⼀开始的问题.
    # from abc import ABCMeta, abstractmethod
    # class Base(metaclass=ABCMeta):
    # @abstractmethod
    # def login(self):
    # pass
    # class Normal(Base):
    # def login(self):
    # pass
    # class Member(Base):
    # def denglu(self): # 这个就没⽤了
    # pass
    # def login(self): # ⼦类对⽗类进⾏实现
    # pass
    # class Admin(Base):
    # def login(self):
    # pass
    # # 项⽬经理写的总⼊⼝
    # def login(obj):
    # print("准备验证码.......")
    # obj.login()
    # print("进⼊主⻚.......")
    # n = Normal()
    # m = Member() # 直接去找父类的login 由于longin是抽象方法不能实现,则会报错,父类静态方法对子类进行约束
    # a = Admin()
    # login(n)
    # login(m)
    # login(a)

    # 总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的
    # ⽅式和⽅法有两种:
    # 1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的
    # 2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专
    # 业, ⽽且错误比较明确.(推荐)

    # ⼆. 异常处理
    # ⾸先, 我们先说⼀下, 什么是异常? 异常是程序在运⾏过程中产⽣的错误. 就好比. 你在
    # 回家路上突然天塌了. 那这个就属于⼀个异常. 总之就是不正常. 那如果程序出现了异常. 怎
    # 么处理呢? 在之前的学习中我们已经写过类似的代码了.
    # 我们先制造⼀个错误. 来看看异常⻓什么样.

    # def chu(a, b):
    # return a/b
    # ret = chu(10, 0)
    # print(ret)
    # 结果:
    # Traceback (most recent call last):
    # File "/Users/sylar/PycharmProjects/oldboy/⾯向对象/day05.py", line 100, in
    # <module>
    # ret = chu(10, 0)
    # File "/Users/sylar/PycharmProjects/oldboy/⾯向对象/day05.py", line 98, in
    # chu
    # return a/b
    # ZeroDivisionError: division by zero
    # 什么错误呢. 除法中除数不能是0. 那如果真的出了这个错. 你把这⼀堆信息抛给客户
    # 么? 肯定不能. 那如何处理呢?

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

    # 那try...except是什么意思呢? 尝试着运⾏xxxxx代码. 出现了错误. 就执⾏except后⾯的
    # 代码. 在这个过程中. 当代码出现错误的时候. 系统会产⽣⼀个异常对象. 然后这个异常会向
    # 外抛. 被except拦截. 并把接收到的异常对象赋值给e. 那这⾥的e就是异常对象. 那这⾥的
    # Exception是什么? Exception是所有异常的基类, 也就是异常的跟. 换句话说. 所有的错误都
    # 是Exception的⼦类对象. 我们看到的ZeroDivisionError 其实就是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⼀般⽤来作为收尾⼯作.

    # 上⾯是处理异常. 我们在执⾏代码的过程中如果出现了⼀些条件上的不对等. 根本不符
    # 合我的代码逻辑. 比如. 参数. 我要求你传递⼀个数字. 你非得传递⼀个字符串. 那对不起. 我
    # 没办法帮你处理. 那如何通知你呢? 两个⽅案.
    # ⽅案⼀. 直接返回即可. 我不管你还不⾏么?
    # ⽅案⼆. 抛出⼀个异常. 告诉你. 我不好惹. 乖乖的听话.
    # 第⼀种⽅案是我们之前写代码经常⽤到的⽅案. 但这种⽅案并不够好. ⽆法起到警⽰作⽤. 所
    # 以. 以后的代码中如果出现了类似的问题. 直接抛⼀个错误出去. 那怎么抛呢? 我们要⽤到
    # raise关键字
    # 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("报错了. ⾃⼰处理去吧")

    # 当程序运⾏到raise. 程序会被中断. 并实例化后⾯的异常对象. 抛给调⽤⽅. 如果调⽤⽅
    # 不处理. 则会把错误继续向上抛出. 最终抛给⽤户. 如果调⽤⽅处理了异常. 那程序可以正常
    # 的进⾏执⾏.
    # 说了这么多. 异常也知道如何抛出和处理了. 但是我们现在⽤的都是⼈家python给的异
    # 常. 如果某⼀天. 你写的代码中出现了⼀个⽆法⽤现有的异常来解决问题. 那怎么办呢? 别着
    # 急. python可以⾃定义异常.
    # ⾃定义异常: 非常简单. 只要你的类继承了Exception类. 那你的类就是⼀个异常类. 就这
    # 么简单. 比如. 你要写⼀个男澡堂⼦程序. 那这时要是来个女的. 你怎么办? 是不是要抛出⼀个
    # 性别异常啊? 好. 我们来完成这个案例:

    # 自定义异常
    # 继承Exception. 那这个类就是⼀个异常类
    # class GenderError(Exception):
    # pass
    # class Person:
    # def __init__(self, name, gender):
    # self.name = name
    # self.gender = gender
    # def nan_zao_tang_xi_zao(person):
    # if person.gender != "男":
    # raise GenderError("性别不对. 这⾥是男澡堂⼦")
    # p1 = Person("alex", "男")
    # p2 = Person("eggon", "蛋")
    #
    # # nan_zao_tang_xi_zao(p1)
    # # nan_zao_tang_xi_zao(p2) # 报错. 会抛出⼀个异常: GenderError
    # # 处理异常
    # try:
    # nan_zao_tang_xi_zao(p1)
    # nan_zao_tang_xi_zao(p2)
    # except GenderError as e:
    # print(e) # 性别不对, 这⾥是男澡堂⼦
    # except Exception as e:
    # print("反正报错了")

    # ok搞定. 但是, 如果是真的报错了. 我们在调试的时候, 最好是能看到错误源⾃于哪⾥?
    # 怎么办呢? 需要引入另⼀个模块traceback. 这个模块可以获取到我们每个⽅法的调⽤信息.
    # ⼜被成为堆栈信息. 这个信息对我们拍错是很有帮助的.
    import traceback # 应用traceback模板,获取对战信息
    # 继承Exception. 那这个类就是⼀个异常类
    # class GenderError(Exception):
    # pass
    # class Person:
    # def __init__(self, name, gender):
    # self.name = name
    # self.gender = gender
    # def nan_zao_tang_xi_zao(person):
    # if person.gender != "男":
    # raise GenderError("性别不对. 这⾥是男澡堂⼦")
    # p1 = Person("alex", "男")
    # p2 = Person("eggon", "蛋")
    # nan_zao_tang_xi_zao(p1)
    # nan_zao_tang_xi_zao(p2) # 报错. 会抛出⼀个异常: GenderError

    # 处理异常 做什么出什么错怎么处理
    # try:
    # nan_zao_tang_xi_zao(p1)
    # nan_zao_tang_xi_zao(p2)
    # except GenderError as e:
    # val = traceback.format_exc() # 获取到堆栈信息
    # print("性别不对. 这⾥是男澡堂⼦") # 性别不对. 这⾥是男澡堂⼦
    # print(val)
    # except Exception as e:
    # print("反正报错了")

    # 结果:
    # 性别不对. 这⾥是男澡堂⼦
    # Traceback (most recent call last):
    # File "/Users/sylar/PycharmProjects/oldboy/⾯向对象/day05.py", line 155, in
    # <module>
    # nan_zao_tang_xi_zao(p2)
    # File "/Users/sylar/PycharmProjects/oldboy/⾯向对象/day05.py", line 144, in
    # nan_zao_tang_xi_zao
    # raise GenderError("性别不对. 这⾥是男澡堂⼦")
    # GenderError: 性别不对. 这⾥是男澡堂⼦
    # 搞定了. 这样我们就能收放⾃如了. 当测试代码的时候把堆栈信息打印出来. 但是当到了
    # 线上的⽣产环境的时候把这个堆栈去掉即可.

    # 五. ⽇志
    # ⾸先, 你要知道在编写任何⼀款软件的时候, 都会出现各种各样的问题或者bug. 这些问
    # 题或者bug⼀般都会在测试的时候给处理掉. 但是多多少少的都会出现⼀些意想不到的异常
    # 或者错误. 那这个时候, 我们是不知道哪⾥出了问题的. 因为很多BUG都不是必现的bug. 如果
    # 是必现的. 测试的时候肯定能测出来. 最头疼的就是这种不必现的bug. 我这跑没问题. 客户那
    # ⼀⽤就出问题. 那怎么办呢?我们需要给软件准备⼀套⽇志系统. 当出现任何错误的时候. 我
    # 们都可以去⽇志系统⾥去查. 看哪⾥出了问题. 这样在解决问题和bug的时候就多了⼀个帮⼿.

    # 那如何在python中创建这个⽇志系统呢? 很简单.
    # 1. 导入logging模块.
    # 2. 简单配置⼀下logging
    # 3. 出现异常的时候(except). 向⽇志⾥写错误信息

    import logging #导入logging模板
    # filename: ⽂件名(可变)
    # format: 数据的格式化输出. 最终在⽇志⽂件中的样⼦
    # 时间-名称-级别-模块: 错误信息
    # datefmt: 时间的格式
    # level: 错误的级别权重, 当错误的级别权重⼤于等于leval的时候才会写⼊⽂件(可变)
    # logging.basicConfig(filename='x1.txt', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
    # datefmt='%Y-%m-%d %H:%M:%S',
    # level=0) # 当前配置表示 10以上的分数会被写⼊⽂件
    # CRITICAL = 50
    # FATAL = CRITICAL
    # ERROR = 40
    # WARNING = 30
    # WARN = WARNING
    # INFO = 20
    # DEBUG = 10
    # NOTSET = 0
    # logging.critical("我是critical") # 50分. 最贵的
    # logging.error("我是error") # 40分
    # logging.warning("我是警告") # 警告 30
    # logging.info("我是基本信息") # 20
    # logging.debug("我是调试") # 10
    # logging.log(2, "我是⾃定义") # ⾃定义. 看着给分

    # 日志格式都是一样的格式
    # 一、单日志个事
    # 1. 导入logging模块.
    # import logging
    # 2. 简单配置⼀下logging
    # logging.basicConfig(filename='x1.txt', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
    # datefmt='%Y-%m-%d %H:%M:%S',
    # level=0) # 可变部分 level=0 可以调整等级,等级多少以上会被写入日志
    # 3. 出现异常的时候(except). 向⽇志⾥写错误信息
    # logging.error("错误信息")

    # 简单做个测试, 应⽤⼀下
    # import logging
    # import traceback
    # logging.basicConfig(filename='日志.txt', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
    # datefmt='%Y-%m-%d %H:%M:%S',
    # level=0)
    # class JackError(Exception): #自定异常
    # pass
    # for i in range(10):
    # try:
    # if i % 3 == 0:
    # raise FileExistsError("文件找不到") # 抛出异常
    # elif i % 3 == 1:
    # raise KeyError("键错了")
    # elif i % 3 == 2:
    # raise JackError("杰克Exception")
    # except FileNotFoundError:
    # val = traceback.format_exc() # 获取错误信息
    # logging.error(val) # 将错误信息写入日志中
    # except KeyError:
    # val = traceback.format_exc()
    # logging.error(val)
    # except JackError:
    # val = traceback.format_exc()
    # logging.error(val)
    # except Exception:
    # val = traceback.format_exc()
    # logging.error(val)

    # 最后, 如果你系统中想要把⽇志⽂件分开. 比如. ⼀个⼤项⽬, 有两个⼦系统, 那两个⼦系
    # 统要分开记录⽇志. ⽅便调试. 那怎么办呢? 注意. ⽤上⾯的basicConfig是搞不定的. 我们要
    # 借助⽂件助⼿(FileHandler), 来帮我们完成⽇志的分开记录

    # 多日志固定格式
    # import logging
    # # 创建⼀个操作⽇志的对象logger(依赖FileHandler)
    # file_handler = logging.FileHandler('l1.log', 'a', encoding='utf-8') # 'l1.log' 文件名可变
    # file_handler.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s"))
    # logger1 = logging.Logger('s1', level=logging.ERROR) # "s1" 日志系统名 可变
    # logger1.addHandler(file_handler)
    # logger1.error('s1')
    #
    # # 再创建⼀个操作⽇志的对象logger(依赖FileHandler)
    # file_handler2 = logging.FileHandler('l2.log', 'a', encoding='utf-8') # 'l2.log' 文件名可变
    # file_handler2.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s -%(levelname)s -%(module)s: %(message)s"))
    # logger2 = logging.Logger('s2', level=logging.ERROR)
    # logger2.addHandler(file_handler2)
    # logger2.error('s2') # "s1" 日志系统名 可变
  • 相关阅读:
    AIX 第3章 指令记录
    AIX 第2章 指令记录
    Oracle Exadata体系笔记
    决定undo表空间的大小
    摘录:官方文档对ROWID虚拟行的定义
    ORA-01102 cannot mount database in EXCLUSIVE mode
    居民身份证号码含义
    ORA-00257错误
    微机原理之 输入输出与中断
    操作系统总结之 输入输出系统(下)
  • 原文地址:https://www.cnblogs.com/z520h123/p/9948940.html
Copyright © 2011-2022 走看看