Python使用元类动态设置property时所有属性绑定最后一个函数问题
问题根因
该问题由Python的闭包延迟绑定特性导致,和你加的deepcopy没有关系:
循环内定义的lambda函数不会在定义时捕获外部变量field_fn、field的当前值,只会在实际被调用时才去查找这两个变量的取值。等到循环执行完成,field_fn已经被赋值为配置字典最后一个键b对应的处理函数lambda x:x-1,field也被赋值为b,所以所有property的getter、setter实际用的都是最后一次循环的变量值,才会出现输出结果全为4的问题。(注:原代码的setter也存在同样的绑定问题,你给obj.a赋值实际会写到_b私有属性上)
修复方案
只需要给lambda添加默认参数,把每次循环迭代的field_fn、field的当前值绑定到lambda的局部作用域即可——Python的函数默认参数会在函数定义阶段完成求值,不会受后续变量修改的影响。
修改后的Meta类代码如下:
class Meta(type): def __new__( cls, clsname: str, bases: Tuple, attrs: Dict[str, Any], fields: Dict[str, Callable] = None, ) -> object: if fields is not None: for field, field_fn in fields.items(): attrs[f"_{field}"] = None attrs[f"{field}"] = property( fget=lambda self, field_fn=field_fn, field=field: deepcopy(field_fn)(getattr(self, f"_{field}")), fset=lambda self, value, field=field: setattr(self, f"_{field}", value), ) return super().__new__(cls, clsname, bases, attrs)
验证结果
修改后运行测试代码,输出为预期的6 4。
内容的提问来源于stack exchange,提问作者Eduardo
相关产品推荐
相关产品推荐

