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

指定format时,自定义logging.Formatter的.属性无法初始化

问题描述

我实现了一个自定义logging.Formatter类MyFormatter,它支持额外的custom_property属性。但在配置该Formatter时,若同时指定format属性,通过.配置的custom_property无法完成初始化;若注释掉format配置项,.属性则能正常初始化自定义属性。

配置代码

"custom_formatter": {
    "()": MyFormatter,
    "style": "{",
    "datefmt": "%Y-%m-%d %H:%M:%S",
    "format": "<custom-format>", # <-- 移除后,'.'即可正常工作
    ".": {
        "custom_property": "value"
    }
}

Formatter实现代码

class MyFormatter(logging.Formatter):
    custom_property: str = "."

    def format(self, record: logging.LogRecord) -> str:
        # ...
        return super().format(record)

请问为何在指定format时,.属性无法生效?


原因分析与解决方案

核心原因

Python logging配置模块对format参数有特殊处理逻辑:当配置中包含format时,模块会优先基于内置的logging.Formatter完成基础实例的初始化,之后再尝试将实例转换为你指定的自定义类类型,这个过程会打断.属性的赋值流程。

具体来说:

  1. 当检测到format键时,logging会先调用logging.Formatter的构造函数,传入format、style、datefmt等参数创建临时实例。
  2. 随后尝试将这个临时实例的类型转换为你通过()指定的MyFormatter,但这个转换过程不会正确继承后续通过.设置的属性——因为.的属性赋值逻辑是在实例创建完成后执行的,而类型转换会覆盖或丢失这些未绑定的属性。
  3. 若没有format参数,logging会直接通过你指定的()工厂类创建实例,此时.的属性赋值可以正常绑定到实例上。

解决方法

方法1:避免使用内置format配置键,改用自定义参数

修改自定义Formatter类,添加构造函数接收格式字符串,直接在配置中传递自定义参数而非format:

class MyFormatter(logging.Formatter):
    def __init__(self, fmt=None, custom_property=".", **kwargs):
        # 先处理自定义属性,再调用父类构造
        self.custom_property = custom_property
        super().__init__(fmt=fmt, **kwargs)

    def format(self, record: logging.LogRecord) -> str:
        # ...
        return super().format(record)

对应的配置修改为:

"custom_formatter": {
    "()": MyFormatter,
    "style": "{",
    "datefmt": "%Y-%m-%d %H:%M:%S",
    "fmt": "<custom-format>",
    "custom_property": "value"
}

方法2:在自定义Formatter构造函数中主动处理属性

如果一定要保留format配置,可以在自定义类的__init__中主动提取并设置自定义属性,避免被父类逻辑覆盖:

class MyFormatter(logging.Formatter):
    custom_property: str = "."

    def __init__(self, **kwargs):
        # 先提取自定义属性,再调用父类构造
        self.custom_property = kwargs.pop('custom_property', self.custom_property)
        super().__init__(**kwargs)

    def format(self, record: logging.LogRecord) -> str:
        # ...
        return super().format(record)

此时配置可以保留.,或者直接将custom_property作为参数传递:

"custom_formatter": {
    "()": MyFormatter,
    "style": "{",
    "datefmt": "%Y-%m-%d %H:%M:%S",
    "format": "<custom-format>",
    "custom_property": "value"
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:30:19