我想使类的属性的属性可以直接通过类的实例访问(而不从其继承)。所以基本上,如果我有:
class A:
@property
def foo(self):
print("foo")
@property
def bar(self):
print("bar")
class B:
def __init__(self):
self._a = A()
我希望能够做b._a.bar
,而不是做b.bar
。基于this answer here,我在B类中尝试了以下方法:
class B:
def __init__(self):
self._a = A()
attrs = [attr for attr in dir(self._a)
if not callable(self._a.__getattribute__(attr))
and not attr.startswith("__")]
for attr in attrs:
setattr(self.__class__, attr,
property(lambda s: s._a.__getattribute__(attr)))
但是当实例化和测试它时,我得到了这些怪异的python时刻之一:
>>> b = B()
foo
bar
>>> b.foo
bar
>>> b.bar
bar
答案 0 :(得分:2)
bar
和foo
,因为执行_a.__getattribue__("foo")
和_a.foo
都会调用属性对象来获取值。
您在B
中设置的两个属性都使用lambda来从property
获取正确的A
。调用lambda时,这是一个常见错误。由于attr
值是从外部范围继承的,因此在评估lambda时不会冻结它。相反,它只是与封闭范围的attr
相同的attr
引用,并相应地进行了更改。因此,您所有的lambda都将具有相同的attr
值。
您可以改为定义B.__getattr__
方法。普通属性查找失败时将调用此方法。
class B:
def __init__(self):
self._a = A()
def __getattr__(self, name):
return getattr(self._a, name)
b = B()
b.bar
# bar
b.foo
# foo