专题篇——测试工程师Python开发实战(05)

发表于:2023-7-19 09:44

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:胡通    来源:51Testing软件测试网原创

#
Python
  第二篇 专题篇
  借人之智,渐入佳境。随着学习的积累和深入,相信读者已经拥有足够的能力,也能在复杂的环境中做对、做好事情,但是如何保持高效率地开发,生产高品质的产品,这是一个值得思考的问题。在当前需求快速变动的背景下,开发人员必须又快又好地完成新功能的迭代。但是一个人就算24小时工作,能干的事情也总是有限的,没有办法全部从头开始“造车”。读者要学会站在巨人的肩膀上,借助他人的智慧,快速而敏捷地完成业务需求,锻炼快速响应能力。
  封装和复用是软件开发中的重要思想,把软件开发中常见的业务场景或工具进行代码级、组件级或架构级的封装,然后在实际软件开发过程中借助已封装的库或第三方库,最大程度地提高软件的开发效率,降低软件的开发成本,缩短软件的开发周期。
  专题篇是依据笔者的工作经验,介绍封装和示例代码级、组件级或架构级的“百宝箱”,共3章:第4章是常用百宝箱,包括自定义异常处理、日志处理、邮件处理、时间处理、多线程处理、Excel处理、配置文件处理、正则表达式处理、命令行参数解析、with正确使用、文件读写处理和序列化处理共12个代码级工具;第5章是高级百宝箱,从消息中间件、缓存中间件和数据库中间件3个维度出发,涉及Kafka、RabbitMQ、Redis、MongoDB、MySQL和SQLite共6个组件级的工具;第6章是通用框架,讲解3个比较通用和流行的框架,包括Web应用框架FastAPI、异步框架Celery和爬虫框架Scrapy。
  第4章 常用百宝箱
  日常开发中,我们会经常遇到相同的代码操作,为了提升开发效率,本章将讲解和演示Python代码级的常用封装或使用方法,并介绍应用较频繁的12个操作,包括自定义异常处理、日志处理、邮件处理、时间处理、多线程处理、Excel处理、配置文件处理、正则表达式处理、命令行参数解析、with正确使用、文件读写处理和序列化处理,供大家学习借鉴。
  4.1  自定义异常处理
  4.1.1  异常含义
  程序在运行的过程中可能会因为权限问题、用户输入问题、第三方API问题、请求参数缺失等问题产生异常,我们可以在程序内部通过捕获异常的语句让程序继续执行,也可以选择通过raise语句抛出异常让程序终止运行,如果不进行异常处理,异常最终会被Python解释器捕获并终止运行程序。
  一般情况下,程序无法处理正常的逻辑执行过程时会发生异常。为了处理程序在运行过程中的异常和错误,Python定义了很多的标准异常和异常处理机制来处理程序运行过程中出现的异常。
  在高级编程语言中,一般都有错误和异常的概念,异常是可以捕获并被处理的,但是错误是不能被捕获的。一个健壮的程序,应尽可能地避免错误,捕获和处理各种异常。
  Python有两种错误很容易辨认:语法错误和异常。Python的语法错误(或称解析错误)是解析代码时出现的错误。当代码不符合Python语法规则时,Python解释器在解析时就会报出SyntaxError语法错误,同时还会明确指出探测到错误的语句和报错原因,如少了冒号、混用中英文符号等。即便Python程序的语法是正确的,在程序运行时,也有可能发生错误,运行期间检测到的错误被称为异常。大多数的异常都不会被程序处理,都以错误信息的形式展现,如除数为0、年龄为负数、数组下标越界等。
  异常处理在任何一门编程语言里都是值得关注的话题,良好的异常处理可以让程序更加健壮,清晰的错误信息能帮助开发人员快速修复问题。
  4.1.2  异常处理方法
  默认情况下,程序发生异常是会终止的,如果我们要避免程序终止执行,可以使用捕获异常的方式获取这个异常的名称,再通过其他的逻辑代码让程序继续运行,这种处理叫作异常处理。
  开发人员可以使用异常处理全面地控制自己的程序。异常处理大大提高了程序的健壮性和人机交互的友好性。在Python语言中,处理异常的关键字主要有try、except、else、finally和raise。
  try关键字:用于检测异常,在程序发生异常时将异常信息交给except关键字。
  except关键字:获取异常并进行处理。
  else关键字:当执行完try关键字域中的代码,如果没有发现异常,则接着执行else关键字域中的代码。
  finally关键字:无论是否发生异常都进入该关键字域进行处理,通常用于处理资源关闭、对象内存释放等必需的操作。
  raise关键字:用于抛出自定义的异常信息使程序不能直接向下执行。
  处理异常的关键字通常组合使用,不同的组合能实现不同的异常处理场景。合理的异常处理不仅能完善程序运行过程中的逻辑,也能提升程序运行的性能。语法如下:
try:
    <语句>  # 待捕获异常的代码
except <异常类>:
    <语句>  # 捕获某种类型的异常
except <异常类> as <变量名>:
    <语句>  # 捕获某种类型的异常并获得对象
else:
    <语句>  # 如果没有异常发生,则执行
finally:
    <语句>  # 退出try时总会执行,不管是否发生了异常,都要执行finally的部分
  上述语法的具体含义如下。
  (1)try中语句在执行时发生异常,搜索except子句,并执行第一个匹配该异常的except子句。
  (2)try中语句在执行时发生异常,却没有匹配的except子句,异常将被递交到外层的try,如果外层不处理该异常,异常将继续向外层传递。如果都不处理该异常,则会传递到最外层,如果还没有处理,就终止异常所在的线程。
  (3)try中语句在执行时没有发生异常,如果有else子句,可执行else子句中的语句。
  (4)无论try中语句在执行时是否发生异常,finally子句中的语句都会执行。
  一个try语句可以对应多个expect子句,但只能对应一个finally子句。我们可以使用try-expect组合检测和处理异常,也可以添加一个可选的else子句处理没有检测到异常的执行代码。而finally子句只用于检测异常和做一些必要的清除工作,例如无论是否发生异常,都要关闭连接。
  4.1.3  自定义异常
  用户自定义异常,只要自定义异常类继承了Exception类即可。在自定义异常类时,我们基本不需要书写很多的代码,表4-1所示是Python中所有标准异常类。
  Python用异常对象来表示异常,当遇到错误,会触发异常。如果异常对象未被捕捉或处理,程序就会被终止执行。
表4-1  Python中所有标准异常类
  如前文所述,Python中自定义异常类型非常简单,只需要从Exception类继承即可。通过创建一个新的异常类,我们可以命名自己的异常。
  在如下示例中我们创建了一个自定义异常类Networkerror,基类为BaseException,用于在异常触发时输出更多的信息:
class Networkerror(BaseException):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        return self.msg
try:
    raise Networkerror('类型错误')
except Networkerror as e:
    print(e)
  在try中,若发生自定义异常,则执行except子句,其中变量e是用于创建Networkerror类的实例。
  如果我们需要自主抛出一个异常,可以使用raise关键字抛出异常,如上述示例中的raise Networkerror('类型错误')。raise的通常语法为“raise异常类名称(描述信息)”,在触发指定类型的异常的同时,附带异常的描述信息。
  在实际调试程序的过程中,有时只获得异常的类型是远远不够的,还需要借助更详细的异常信息才能解决问题。捕获异常时,有两种方式可获得更多的异常信息,分别是:
  使用sys库中的exc_info方法;
  使用traceback库中的相关函数。
  TabError的解决方法
  Python文件运行时报错:
  TabError:?inconsistent?use?of?tabs?and?spaces?in?indentation
  究其原因是Python文件中混用Tab和Space实现格式缩进,通常使用外部编辑器编辑Python文件时,会自动采用Tab进行格式缩进。
  解决方法为将Tab转换成4个Space。
  4.1.4  封装示例
  在进行Web开发的工程中,如果采用Flask框架,那么需要自定义异常处理类,方便统一进行异常的处理。此时自定义的异常处理类应该继承自HTTPException,自定义的内容通常包含如下几点:
  定义想要返回的错误信息的JSON格式,如内部错误码、错误信息等;
  更改返回的响应头,返回JSON格式的信息响应头应设为'Content-Type': 'application/json';
  与HTTPException一样,定义状态码。
  我们自定义异常类APIException,返回的信息包括内部错误码、错误信息和请求的URL如代码清单4-1所示。
# -*- coding: utf-8 -*-
# @Time : 2022/3/17 4:21 下午
# @Project : ExceptionTestDemo
# @File : APIException.py
# @Author : hutong
# @Describe: 微信公众号:大话性能
# @Version: Python3.9.8
 
from flask import request, json
from werkzeug.exceptions import HTTPException
 
class APIException(HTTPException):
    code = 500
    msg = 'sorry, we made a mistake!'
    error_code = 999
    def __init__(self, msg=None, code=None, error_code=None, headers=None):
        if code:
            self.code = code
        if error_code:
            self.error_code = error_code
        if msg:
            self.msg = msg
        super(APIException, self).__init__(msg, None)
    def get_body(self, environ=None):
        body = dict(
            msg=self.msg,
            error_code=self.error_code,
            request=request.method + ' ' + self.get_url_no_param()
        )
        text = json.dumps(body)
        return text
    def get_headers(self, environ=None):
        """Get a list of headers."""
        return [('Content-Type', 'application/json')]
    @staticmethod
    def get_url_no_param():
        full_path = str(request.full_path)
        main_path = full_path.split('?')
        return main_path[0]
代码清单4-1  APIException
  有了APIException类,我们就可以自由地定义各种状态码以及对应的异常信息,然后在合适的位置抛出异常,如代码清单4-2所示。
# -*- coding: utf-8 -*-
# @Time : 2022/3/17 5:21 下午
# @Project : ExceptionTestDemo
# @File : APIExceptionExample.py
# @Author : hutong
# @Describe: 微信公众号:大话性能
# @Version: Python3.9.8
 
import APIException
 
class Success(APIException):
    code = 201
    msg = 'ok'
    error_code = 0
class ServerError(APIException):
    code = 500
    msg = 'sorry, we made a mistake!'
    error_code = 999
class ParameterException(APIException):
    code = 400
    msg = 'invalid parameter'
    error_code = 1000
class NotFound(APIException):
    code = 404
    msg = 'the resource are not found'
    error_code = 1001?
代码清单4-2  APIExceptionExample
  自定义异常类可以帮助我们在需要的地方抛出异常。在发生异常时,我们可以对照状态码去查找对应的异常类,非常方便。注意,虽然此处表述为异常类,但是我们可以在类中定义响应成功的返回,例如代码清单4-2中定义的状态码201对应的异常类,可以作为响应成功的返回。
版权声明:51Testing软件测试网获得作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号