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

Python attrs转换器中使用lambda函数出现异常行为的问题求助

Lambda转换器在attrs字段转换器中的闭包陷阱问题

在使用attrs库的field_transformer自动创建依赖元数据的转换器时,用lambda函数作为转换器会出现异常行为:元数据未被正确识别,调换字段顺序后所有字段共用最后一个字段的元数据值。

代码示例

import attrs

def add(x, y=10):
    return x + y

def func(cls, fields):
    results = []
    for f in fields:
        y = f.metadata.get('add', None)
        converter = lambda x: add(x, y) if (y is not None) else add(x)
        print('Name:', f.name, y, converter(0))
        results.append(f.evolve(converter=converter))
    return results

异常现象

  1. 字段a带元数据、b不带的情况
Data1 = attrs.make_class('Data1', 
                         {'a': attrs.field(default=1, metadata={'add': 5}), 
                          'b': attrs.field(default=1)}, 
                          field_transformer=func)
d1= Data1()
d1

输出:

Name: a 5 5
Name: b None 10
实例结果:Data1(a=11, b=11)

本该a用y=5得到6,b用默认y=10得到11,但实际两者都是11。

  1. 调换字段顺序后
Data2 = attrs.make_class('Data2', 
                         {'b': attrs.field(default=1), 
                          'a': attrs.field(default=1, metadata={'add': 5})},
                         field_transformer=func)
d2 = Data2()
d2

输出:

Name: b None 10
Name: a 5 5
实例结果:Data2(b=6, a=6)

本该b用默认y=10得到11,a用y=5得到6,但实际两者都是6。

原因分析

这是Python闭包的延迟绑定特性导致的:lambda函数中的y变量并不是在定义时就捕获当前循环的y值,而是在lambda被调用(即attrs处理字段时)才会去查找y的当前值。循环结束后,y会保留最后一次循环的赋值结果,所以所有lambda都会共用这个最终的y值:

  • Data1循环最后y是None,所以两个转换器都用y=None,调用add(x,10)得到11;
  • Data2循环最后y是5,所以两个转换器都用y=5,调用add(x,5)得到6。

解决方案

通过给lambda添加默认参数,在定义时就捕获当前循环的y值,避免延迟绑定的问题:

def func(cls, fields):
    results = []
    for f in fields:
        y = f.metadata.get('add', None)
        # 用默认参数y=y捕获当前循环的y值
        converter = lambda x, y=y: add(x, y) if (y is not None) else add(x)
        print('Name:', f.name, y, converter(0))
        results.append(f.evolve(converter=converter))
    return results

修改后再运行两个Data类,就能得到预期结果:

  • Data1实例:Data1(a=6, b=11)
  • Data2实例:Data2(b=11, a=6)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 17:13:17