python学习笔记:第19天 类的约束

发布时间:2019-04-01 21:41:11编辑:auto阅读(2035)

    一、类的约束

    真正写写项目的代码时都是多人协作的,所以有些地方需要约束程序的结构。也就是说,在分配任务之前就应该把功能定义好,然后分别交给底下的程序员来完成相应的功能。

    在python中有两种办法来约束类的方法:

    • 第一种方法使用继承的特性:提取⽗类,然后在⽗类中定义好⽅法,在这个⽅法中什么都不⽤⼲,就抛⼀个异常就可以了。这样所有的⼦类都必须重写这个⽅法,否则访问的时候就会报错。
    class Base:
        def run(self):
            raise NotImplementedError('子类没有实现login方法')
            
    class Foo1(Base):
        def run(self):
            print('Foo1\'s Function')
            
    class Foo2(Base):
        def run(self):
            print('Foo2\'s Function')
            
    class Foo3(Base):
        def run3(self):                         # Foo3中没有按规范重写run方法,这里会报错
            print('Foo3\'s Function')
            
    l1 = [Foo1(), Foo2(), Foo3()]
    for item in l1:
        item.run()

    结果如下:

    • 第二种方法是使⽤元类来描述⽗类:在元类中给出⼀个抽象⽅法,这样⼦类就不得不给出抽象⽅法的具体实现,也可以起到约束的效果。
    from abc import ABCMeta, abstractmethod                 # 导入抽象元类和定义抽象方法的装饰器
    
    class Aminal(metaclass=ABCMeta):                        # 在创建类的时候指定要使用ABCMeta元类
        @abstractmethod
        def eat(self):                                      # 然后定义了一个抽象方法
            pass
    
    class Cat(Aminal):
        pass
    
    c = Cat()
    c.eat()

    上面的结果告诉我们,必须要实现抽象类才能实例化这个对象,手动重写这个方法后就能正常使用了:

    from abc import ABCMeta, abstractmethod
    
    class Aminal(metaclass=ABCMeta):
        @abstractmethod
        def eat(self):
            pass
    
    class Cat(Aminal):
        def eat(self):
            print('猫抓老鼠')
    
    c = Cat()
    c.eat()
    
    # 结果:
    # 猫抓老鼠

    总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:

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

    二、异常处理:

    异常:所谓异常就是程序在运行过程中出现的异常,这种是事先不能预知的,只有在程序运行时才会出现,所以我们要编写异常处理的程序来应对。

    try:
        坑能抛出异常的语句
    
    except 异常1:
        捕获异常1时处理的步骤
    
    except 异常2:
        捕获异常2时处理的步骤
    
    finally:
        try语句块最后执行的操作

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

    我们先来看个异常的例子:

    # 计算a+b
    
    def cal(a, b):
        try:
            return a + b
        except TypeError as v:                      # 捕获到TypeError异常时执行这段代码块的处理步骤
            print('输入正确的数字(整数或者小数)')
    
    cal(10, '胡辣汤')
    
    # 这个时候会执行自定义的处理方法
    # 输入正确的数字(整数或者小数)

    上面我们捕获到异常都是python自定义的异常(TypeErrorExcept等),在一些特定的场景中可能python内置的异常种类不能全部适用,所以我们需要抛出自定义的异常。那么自定义的异常要怎么写?⾃定义异常: 非常简单,只要你的类继承了Exception类,那你的类就是⼀个异常类,就这么简单。

    class MyException(Exception):                   # 类继承了Exception类,这个类就是⼀个异常类了
        pass
    
    def cal(a, b):
        if ((type(a) == int) or type(a) == float) and ((type(b) == int) or type(b) == float):
            return a + b
        else:
            raise MyException('输入正确的数字(整数或者小数)')         #  当判断条件为假时我们手动抛出这个自定义异常
    
    try:
        cal(10, '胡辣汤')
    except MyException as m:                        # 然后这里捕获异常
        print('捕捉到自定义的异常')                     # 捕获到异常后执行具体的处理步骤
    
    except Exception as e:                          # Exception可以放在最后面,可以捕获所有异常
        print('出错了')
    finally:
        print('计算完成')                           # 最后finally语句结尾
    
    # 执行结果:
    # 捕捉到自定义的异常
    # 计算完成

    这里再介绍一个知识点:查看具体的错误信息,当我们真正在调试的时候,最好是能看到错误源⾃于哪⾥,怎么办呢?需要引入另⼀个模块traceback这个模块可以获到我们每个⽅法的调⽤信息,⼜被成为堆栈信息,这个信息对我们拍错是很有帮助的,使用方法如下:

    import traceback
    def cal(a, b):
        try:
            return a + b
        except TypeError as v:
            print(traceback.format_exc())           # 这里可以把错误的堆栈信息打印出来,可以方便调试
    
    cal(10, '胡辣汤')

    三、MD5加密

    MD5消息摘要算法(MD5 Message-Digest Algorithm)是⼀种不可逆的加密算法,它是可靠的,并且安全的(关于MD5加密这一块这里不多做介绍,后面会另外写博客介绍加密/解密这一块的)。在python中我们不需要⼿写这⼀套算法,只需要引入⼀个叫hashlib的模块就能搞定MD5的加密⼯作:

    import hashlib
    
    obj = hashlib.md5()                 # 返回一额hash对象
    obj.update("alex".encode("utf-8")) # 加密的必须是字节
    miwen = obj.hexdigest()
    print(miwen)                       # 534b44a19bf18d20b71ecc4eb77c572f

    这样加密一串字符真的安全吗,我们在网上有很多在线解密MD5的工具,这个这个字符串放到那些网站上一解密就出来了,如下图:

    那么这是为什么呢,这是因为MD5存在的历史悠久,很多字符已经被加密记录到一个库中了,这种所谓的解密就是再这个库中查找记录,如果找到了就成为解密成功,那我们应该怎么避免这种问题呢,其实很简单,我们在生成hash对象时加点盐(salt)就OK了:

    import hashlib
    
    obj = hashlib.md5(b'sjfqwjbekwjbckwo23o920fl2')
    obj.update("alex".encode("utf-8"))
    miwen = obj.hexdigest()
    print(miwen)                        # 19c7d5410eda9452205f6b59e8ba2c33  
                                        # 这时候在拿去解密他就解密不了了

    四、日志(logging模块)

    logging模块的使用方法:

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

    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=30)    # 当前配置表示30以上的分数会被写⼊⽂件
    # 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, "我是⾃定义") # ⾃定义. 看着给分

    最后, 如果你系统中想要把⽇志⽂件分开,比如,⼀个⼤项⽬,有两个⼦系统,那两个⼦系统要分开记录⽇志,⽅便调试,那怎么办呢?注意,⽤上⾯的basicConfig是搞不定的,我们要借助⽂件助⼿(FileHandler),来帮我们完成⽇志的分开记录;这里如果要修改日志的文件编码格式也是在这里改的:

    import logging
    # 创建⼀个操作⽇志的对象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('s1', level=logging.ERROR)
    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('s2', level=logging.ERROR)
    logger2.addHandler(file_handler2)
    logger2.error('我是B系统')

关键字

上一篇: numpy

下一篇: 约束和异常处理