You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求优化Python 2.7动态进度条代码(仅用标准库)

Python 2.7 动态进度条代码精简优化

问题概述

我为调试应用开发了一个动态进度条函数,功能符合预期,但需要帮助精简代码以提升效率。该代码基于Python 2.7.15,仅能使用标准库,无法引入tkinter等第三方模块。当前代码通过3种分支处理进度条填充与百分比文本的叠加逻辑,希望能优化简化这段代码。

原代码

def progress_bar(current_value, **kwargs):
    top_left_border = u'\u2554'.encode('utf-8')
    top_right_border = u'\u2557'.encode('utf-8')
    bottom_left_border = u'\u255A'.encode('utf-8')
    bottom_right_border = u'\u255D'.encode('utf-8')
    horizontal_border = u'\u2550'.encode('utf-8')
    vertical_border = u'\u2551'.encode('utf-8')
    color_border = '\33[38;5;3m'
    color_fg = '\33[38;5;4m'
    color_bg = '\33[48;5;4m'
    color_inverted_fg = '\33[38;5;0m'
    color_end = '\33[0m'

    b_val = int(current_value)
    b_width = 50
    b_max = 100
    b_min = 0
    for k, v in kwargs.items():
        if k.lower() == 'width': b_width = v
        elif k.lower() == 'max': b_max = v
        elif k.lower() == 'min': b_min = v
        elif k.lower() == 'fg':
            if 0 <= v <= 255:
                color_fg = '\33[38;5;{}m'.format(v)
        elif k.lower() == 'bg':
            if 0 <= v <= 255:
                color_bg = '\33[48;5;{}m'.format(v)
        elif k.lower() == 'reverse':
            if 0 <= v <= 255:
                color_inverted_fg = '\33[38;5;{}m'.format(v)
        elif k.lower() == 'border':
            if 0 <= v <= 255:
                color_border = '\33[38;5;{}m'.format(v)

    if b_min >= b_max:
        print color('Minimum value cannot be greater than or equal to maximum value.', 'red')
        return
    if b_val < b_min: b_val = b_min
    if b_val > b_max: b_val = b_max
    if b_width < 10: b_width = 10

    # top border
    print color_border + top_left_border + horizontal_border * (b_width - 2) + top_right_border + color_end

    # progress bar fill count, percentage string and starting position of string
    fill_cnt = int(round(float(b_val - b_min) / (b_max - b_min) * (b_width - 2)))     # filled spaces
    fill_pct = str(int(round((float(b_val - b_min) / (b_max - b_min)) * 100))) + '%'  # % string
    pct_pos = int(round((b_width - 2) / 2) - round((len(fill_pct) / 2) - 1))          # start position of %

    # build the percentage bar string & percentage text
    b_bar = color_border + vertical_border + color_end

    if fill_cnt >= pct_pos:
        # if filled bar position ends after start of text
        num_dig = pct_pos - 1  # number of spaces before text
        b_bar += color_bg + ' ' * num_dig + color_end
        if fill_cnt < pct_pos + len(fill_pct):
            # if filled bar ends within text block
            num_dig = fill_cnt - pct_pos + 1  # how many digits of text are filled
            b_bar += color_bg + color_inverted_fg + fill_pct[:num_dig] + color_end
            b_bar += color_fg + fill_pct[num_dig:] + color_end  # unfilled text digits after
            num_dig = (b_width - 2) - (pct_pos + len(fill_pct) - 1)  # blank spaces after text
            b_bar += color_fg + ' ' * num_dig + color_border + vertical_border + color_end
        else:
            # if the filled bar position ends after the end of text
            b_bar += color_bg + color_inverted_fg + fill_pct + color_end  # percentage text
            num_dig = fill_cnt - (pct_pos + len(fill_pct) - 1)  # filled bar positions after end of text
            b_bar += color_bg + ' ' * num_dig + color_end
            num_dig = (b_width - 2) - fill_cnt  # number of blanks after filled bar
            b_bar += color_fg + ' ' * num_dig + color_border + vertical_border + color_end
    else:
        # if the filled bar position end before start of text
        b_bar += color_bg + ' ' * fill_cnt + color_end  # filled bar spaces
        num_dig = pct_pos - fill_cnt - 1  # blanks after fill & before start of text
        b_bar += color_fg + ' ' * num_dig + fill_pct + color_end
        num_dig = (b_width - 2) - (pct_pos + len(fill_pct) - 1)  # blanks after end of text
        b_bar += color_fg + ' ' * num_dig + color_border + vertical_border + color_end
    print b_bar

    # bottom border
    print color_border + bottom_left_border + horizontal_border * (b_width - 2) + bottom_right_border + color_end

使用说明

调用方式:progress_bar(value, **kwargs)
可选参数说明:

  • width=50:进度条整体宽度(最小值10)
  • max=100:进度的最大值
  • min=0:进度的最小值
  • fg:未填充区域及未被覆盖文本的前景色索引(范围0-255)
  • bg:填充区域的背景色索引(范围0-255)
  • reverse:被填充区域覆盖的文本的前景色索引(范围0-255)
  • border:进度条边框的颜色索引(范围0-255)

精简优化后的代码

def progress_bar(current_value, **kwargs):
    # 边框字符统一管理,一次性编码避免重复操作
    borders = {
        'tl': u'\u2554'.encode('utf-8'),
        'tr': u'\u2557'.encode('utf-8'),
        'bl': u'\u255A'.encode('utf-8'),
        'br': u'\u255D'.encode('utf-8'),
        'h': u'\u2550'.encode('utf-8'),
        'v': u'\u2551'.encode('utf-8')
    }
    # 颜色配置默认值
    colors = {
        'border': '\33[38;5;3m',
        'fg': '\33[38;5;4m',
        'bg': '\33[48;5;4m',
        'reverse_fg': '\33[38;5;0m',
        'end': '\33[0m'
    }
    # 参数默认值
    params = {
        'width': 50,
        'max': 100,
        'min': 0
    }

    # 批量处理传入参数
    for k, v in kwargs.items():
        k_lower = k.lower()
        if k_lower in params:
            params[k_lower] = v
        elif k_lower in ['fg', 'bg', 'reverse', 'border']:
            if 0 <= v <= 255:
                color_key = 'reverse_fg' if k_lower == 'reverse' else k_lower
                # 根据参数类型选择前景/背景色控制码
                code_type = 38 if k_lower != 'bg' else 48
                colors[color_key] = '\33[{};5;{}m'.format(code_type, v)

    # 解构参数,简化后续调用
    b_val = int(current_value)
    b_width, b_max, b_min = params['width'], params['max'], params['min']
    bar_inner_width = b_width - 2

    # 参数校验与修正
    if b_min >= b_max:
        print '\33[38;5;1mMinimum value cannot be greater than or equal to maximum value.\33[0m'
        return
    b_val = max(b_min, min(b_val, b_max))
    b_width = max(10, b_width)

    # 计算核心进度值,避免重复计算
    progress_ratio = float(b_val - b_min) / (b_max - b_min)
    fill_cnt = int(round(progress_ratio * bar_inner_width))
    fill_pct = '{}%'.format(int(round(progress_ratio * 100)))
    # 简化文本居中计算,用整数除法更稳定
    pct_start = (bar_inner_width - len(fill_pct)) // 2
    text_len = len(fill_pct)

    # 构建进度条内部内容,拆分逻辑减少分支
    inner_parts = []
    # 添加已填充区域
    if fill_cnt > 0:
        inner_parts.append(colors['bg'] + ' ' * fill_cnt + colors['end'])
    
    # 处理文本与填充的叠加关系
    text_filled = max(0, min(fill_cnt - pct_start, text_len))
    text_unfilled = text_len - text_filled

    if fill_cnt >= pct_start:
        # 填充覆盖了部分或全部文本
        if text_filled > 0:
            inner_parts.append(colors['bg'] + colors['reverse_fg'] + fill_pct[:text_filled] + colors['end'])
        if text_unfilled > 0:
            inner_parts.append(colors['fg'] + fill_pct[text_filled:] + colors['end'])
        # 添加剩余空白区域
        remaining = bar_inner_width - fill_cnt
        if remaining > 0:
            inner_parts.append(colors['fg'] + ' ' * remaining + colors['end'])
    else:
        # 填充未到达文本区域
        inner_parts.append(colors['fg'] + ' ' * (pct_start - fill_cnt) + colors['end'])
        inner_parts.append(colors['fg'] + fill_pct + colors['end'])
        remaining = bar_inner_width - (pct_start + text_len)
        if remaining > 0:
            inner_parts.append(colors['fg'] + ' ' * remaining + colors['end'])

    # 拼接完整进度条行
    bar_line = (colors['border'] + borders['v'] + colors['end'] +
                ''.join(inner_parts) +
                colors['border'] + borders['v'] + colors['end'])

    # 打印完整进度条
    print colors['border'] + borders['tl'] + borders['h'] * bar_inner_width + borders['tr'] + colors['end']
    print bar_line
    print colors['border'] + borders['bl'] + borders['h'] * bar_inner_width + borders['br'] + colors['end']

优化要点说明

  1. 配置结构化:用字典统一管理边框字符、颜色和参数默认值,替代零散变量,提升代码可读性和维护性。
  2. 简化参数处理:通过字典键匹配替代多分支if-elif,减少冗余代码。
  3. 合并重复计算:提前计算progress_ratio,避免多次重复计算进度占比,提升运行效率。
  4. 消除嵌套分支:将进度条填充、文本展示拆分为独立逻辑块拼接,原有的三层分支嵌套简化为两层,逻辑更清晰。
  5. 简化边界校验:用max/min函数一行完成值的边界修正,替代多分支if判断。
  6. 优化居中计算:用整数除法//替代多次round操作,结果更稳定且代码更简洁。

内容的提问来源于stack exchange,提问作者Kryo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 17:16:07