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

为何两段Python动态属性定义代码返回值不一致?

为什么两段Python脚本表现不一致?

第一段脚本

class Q:
  def __init__(self):
    self._foo = 123
    self._bar = 456
    
    self._properties = {
      "foo": property(lambda self: getattr(self, "_foo")),
      "bar": property(lambda self: getattr(self, "_bar"))
    }

  def __getattr__(self, name):
    if name not in self._properties:
      raise AttributeError(f"Property '{name}' does not exist")
    return self._properties[name].__get__(self, self.__class__)

q = Q()
print(q.foo)
print(q.bar)

输出:

123
456

第二段脚本

class Q:
  def __init__(self):
    self._foo = 123
    self._bar = 456

    self._properties = {
      k: property(lambda self: getattr(self, f"_{k}")) for k in ['foo', 'bar']
    }

  def __getattr__(self, name):
    if name not in self._properties:
      raise AttributeError(f"Property '{name}' does not exist")
    return self._properties[name].__get__(self, self.__class__)

q = Q()
print(q.foo)
print(q.bar)

输出:

456
456

问题根源

这是Python中lambda表达式在循环场景下的延迟绑定特性引发的问题:

  • 循环内定义的lambda不会在创建时立即捕获循环变量k的当前值,而是等到lambda被调用时,才会去查找k的当前值。
  • 字典推导式执行完毕后,循环变量k的最终值是'bar',因此两个lambda在实际调用时,都会使用这个最终值来拼接属性名,最终都获取到_bar的值,导致输出重复。

而第一段脚本里的lambda直接写死了"_foo"和"_bar"字符串,没有依赖循环变量,每个lambda都绑定了固定的目标属性,调用时自然能返回正确结果。

修复方案

要在循环中正确生成lambda,需要通过参数默认值强制捕获循环变量的当前值,修改后的字典推导式如下:

self._properties = {
  k: property(lambda self, k=k: getattr(self, f"_{k}")) for k in ['foo', 'bar']
}

这里给lambda新增了k=k的参数,默认值会在lambda定义时就绑定当前循环迭代的k值,避免后续调用时使用循环变量的最终值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:34:49