动态添加属性会创建不需要的别名

adding properties dynamically creates unwanted aliases

我想按如下方式将属性动态添加到我的 class,但是我最终创建了别名。我怎样才能避免这种情况?

class A:

    def __init__(self, a, b):
        self._a = a
        self._b = b

for attr in ('a', 'b'):
    f = lambda self: getattr(self, '_'+attr)
    setattr(A, attr, property(f, None))

a = A(0,1)

print(a.a)
print(a.b)

但是这会产生:

1
1

编辑:

关于闭包作用域的评论是相关的,但这留下了一个问题,即是否可以动态生成引用 self open 的某些属性的属性。

特别是关于上面的例子:我如何设置 属性 使得 a.a returns 0 而不是 1?如果我只是尝试将属性参数传递给 lambda 函数,则需要传递此属性,因此这将不起作用。

为了获得所需的结果,您需要将 lambda 包装在另一个函数中,如下所示:

def make_fget(attr):
    return lambda self: getattr(self, '_' + attr)

这样,当您调用 make_fget 时,本地名称 attr 绑定到传递的参数。

您可以像在原始代码中一样在循环中调用它:

for attr in ('a', 'b'):
    setattr(A, attr, property(make_fget(attr), None))

这里的区别在于,在您的原始版本中,循环本质上是在每次迭代时重新分配 attr,而 lambda 当时仅在外部范围(循环)中查看 attr它被调用,它将以上次迭代中分配的任何内容结束。

通过包装在另一个函数中,在每次循环迭代中,您实际上为返回的 lambda 创建了一个新的外部作用域(函数调用),名称 attr 绑定到传递的参数。