如何用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
相关产品推荐
相关产品推荐

