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

如何用Python logging模块实现循环进度无换行输出?

用Python logging模块实现循环进度的无换行输出

当然可以用logging实现这种效果,但logging本身没有内置的logging.end()上下文管理器,需要通过自定义Handler或者临时修改Handler的输出行为来实现,下面是几种可行的方案:

方案一:自定义无换行StreamHandler

默认的logging.StreamHandler会在每条日志后自动添加换行符,我们可以重写它的emit方法,取消自动换行,以此模拟print(..., end='')的效果:

import logging
import sys

class NoNewlineStreamHandler(logging.StreamHandler):
    def __init__(self, stream=None):
        super().__init__(stream)
        self.terminator = ''  # 取消默认的换行符

    def emit(self, record):
        try:
            msg = self.format(record)
            self.stream.write(msg)
            if self.terminator:
                self.stream.write(self.terminator)
            self.flush()
        except Exception:
            self.handleError(record)

# 配置日志
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.handlers.clear()  # 避免重复添加Handler

handler = NoNewlineStreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter('%(message)s'))  # 只输出消息内容
logger.addHandler(handler)

# 循环输出进度
for n in range(99999999):
    if n % 99999 == 0:
        msg = f'Completed {n} iterations'
        # 输出消息后添加对应长度的退格符,让光标回到行首
        logger.info(msg + '\b' * len(msg))

方案二:用上下文管理器临时修改Handler的终止符

如果你想要类似题目中with logging.end(''):的写法,可以自己实现一个上下文管理器,临时修改默认StreamHandler的terminator属性:

import logging
import sys
from contextlib import contextmanager

@contextmanager
def logging_no_newline():
    # 找到输出到stdout的StreamHandler
    target_handler = None
    for handler in logging.getLogger().handlers:
        if isinstance(handler, logging.StreamHandler) and handler.stream is sys.stdout:
            target_handler = handler
            break
    
    if target_handler:
        original_terminator = target_handler.terminator
        target_handler.terminator = ''
        try:
            yield
        finally:
            target_handler.terminator = original_terminator
    else:
        yield

# 基础日志配置
logging.basicConfig(level=logging.INFO, format='%(message)s')
logger = logging.getLogger(__name__)

# 使用上下文管理器实现无换行输出
with logging_no_newline():
    for n in range(99999999):
        if n % 99999 == 0:
            msg = f'Completed {n} iterations'
            logger.info(msg + '\b' * len(msg))

更可靠的替代:用回车符\r覆盖整行

退格符\b在部分终端环境下可能表现不稳定,换成回车符\r(将光标移到行首)的方式更可靠,不需要额外的退格符:

# 以方案二为例,修改消息内容即可
with logging_no_newline():
    for n in range(99999999):
        if n % 99999 == 0:
            # \r会让光标回到行首,下一次输出直接覆盖当前行内容
            logger.info(f'\rCompleted {n} iterations')

注意事项

  • 如果日志同时输出到文件,退格符或回车符会被写入文件导致内容混乱,建议给进度日志单独配置只输出到控制台的Handler。
  • 部分终端(如Windows命令提示符)对\r的支持可能需要额外配置,不过大部分现代终端都能正常处理。

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

相关产品推荐
方舟 Agent Plan

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

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