• 重构代码用warning提醒调用者API发生变化


    重构代码用warning提醒调用者API发生变化

    1.概述

    在开发过程,我们开发的API如果需要修改,这个修改会影响已经在使用API的开发者,那么他们需要修改调用这个API的方式。当API修改后,我们要怎么通知他们那?
    我们可以使用python内置的warnings模块来通知开发者API已修改,需要尽快修改代码。

    2.warning模块介绍

    2.1.warning使用示例

    下面我们来开发一个模块,计算一辆汽车在一定的平均速度和一段时长下,能够运行的距离。
    speed默认的单位是英里/小时,时长的单位是小时。

    #根据传入的速度和时长计算能够运行多远的距离
    def print_distance(speed, duration):
        distance = speed * duration
        print(f'{distance} miles')
    
    print_distance(5, 2.5)
    
    
    # 调用这个功能计算运行距离
    print_distance(1000, 3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    上面是第一个版本,现在要为这个模块的速度和时长增加不同的单位,让他计算的功能得到扩展。我们可以让调用者通过可选的关键字参数指定速度和时长的单位。

    # 将单位对应的换算公式定义到字典常量
    CONVERSIONS = {
        'mph': 1.60934 / 3600 * 1000,   # m/s
        'hours': 3600,                  # seconds
        'miles': 1.60934 * 1000,        # m
        'meters': 1,                    # m
        'm/s': 1,                       # m
        'seconds': 1,                   # s
    }
    
    def convert(value, units):
        rate = CONVERSIONS[units]
        return rate * value
    
    def localize(value, units):
        rate = CONVERSIONS[units]
        return value / rate
    
    # 参数设计为可选的关键字参数
    def print_distance(speed, duration, *,
                       speed_units='mph',
                       time_units='hours',
                       distance_units='miles'):
        norm_speed = convert(speed, speed_units)
        norm_duration = convert(duration, time_units)
        norm_distance = norm_speed * norm_duration
        distance = localize(norm_distance, distance_units)
        print(f'{distance} {distance_units}')
    
    
    # Example 4
    print_distance(1000, 3,
                   speed_units='meters',
                   time_units='seconds')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    上面的API可以支持的单位了,但是还无法通知开发者这个API已修改,下面加入warning提醒开发者这个API已修改。

    在每个可选的关键字参数加一个判断,如果开发者未指定单位,那么告诉他API可以通过指定单位调用。如果没有传递单位也是可以用的,告诉开发者一直不修改,可能以后就会发生调用错误。

    import warnings
    
    def print_distance(speed, duration, *,
                       speed_units=None,
                       time_units=None,
                       distance_units=None):
        # 在每个参数上添加判断,如果未传入值则提醒调用者,这个API已经发生了改变
        if speed_units is None:
            warnings.warn(
                'speed_units required', DeprecationWarning)
            speed_units = 'mph'
    
        if time_units is None:
            warnings.warn(
                'time_units required', DeprecationWarning)
            time_units = 'hours'
    
        if distance_units is None:
            warnings.warn(
                'distance_units required', DeprecationWarning)
            distance_units = 'miles'
    
        norm_speed = convert(speed, speed_units)
        norm_duration = convert(duration, time_units)
        norm_distance = norm_speed * norm_duration
        distance = localize(norm_distance, distance_units)
        print(f'{distance} {distance_units}')
    
    # 调用时不指定单位
    print_distance(1000, 3,)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    运行上面的代码,下面输出了正确的结果,同时给出了API修改的提示。

    3000.0 miles
     DeprecationWarning: speed_units required
      warnings.warn(
     DeprecationWarning: time_units required
      warnings.warn(
     DeprecationWarning: distance_units required
      warnings.warn(
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.2.stacklevel优化提醒

    上面的代码虽然实现了提醒开发者API已修改,但是它有两个缺陷。

    • 每个参数都要重复添加if判断语句,使得程序不易维护
    • 运行上面的代码输出的3处提醒语句的位置都是warings.war()语句位置输出的并不是调用print_distance函数位置输出,其实调用print_distance的位置更加重要,因为它能够提醒作者开发者那行语句没有给关键字参数传值。

    waring.warn函数提供了一个名为stacklevel参数,让我们可以根据栈的深度指出触发这条警告的位置,这项功能可以封装成辅助函数。

    def require(name, value, default):
        if value is not None:
            return value
        warnings.warn(
            f'{name} will be required soon, update your code',
            DeprecationWarning,
            stacklevel=3)
        return default
    
    def print_distance(speed, duration, *,
                       speed_units=None,
                       time_units=None,
                       distance_units=None):
        speed_units = require('speed_units', speed_units, 'mph')
        time_units = require('time_units', time_units, 'hours')
        distance_units = require(
            'distance_units', distance_units, 'miles')
    
        norm_speed = convert(speed, speed_units)
        norm_duration = convert(duration, time_units)
        norm_distance = norm_speed * norm_duration
        distance = localize(norm_distance, distance_units)
        print(f'{distance} {distance_units}')
    print_distance(1000, 3,)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    运行上面的代码,下面输出的提示信息位置都是在调用print_distance位置

    3000.0 miles
    106: DeprecationWarning: speed_units will be required soon, update your code
      print_distance(1000, 3,)
    106: DeprecationWarning: time_units will be required soon, update your code
      print_distance(1000, 3,)
    106: DeprecationWarning: distance_units will be required soon, update your code
      print_distance(1000, 3,)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    C语言实现给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。
    2023秋招——大数据研发工程师提前批一面
    利用多核的Rust快速Merkle tree
    【英语语法】so
    表白墙(web版)
    IDEA
    数组原地哈西一类题一网打尽
    Visual Studio 2019中的安全问题
    用 Hugging Face 推理端点部署 LLM
    【黑马程序员】SpringCloud——微服务
  • 原文地址:https://blog.csdn.net/m0_38039437/article/details/128143342