Python 动态创建指向属性的属性';s属性

Python 动态创建指向属性的属性';s属性,python,oop,properties,Python,Oop,Properties,我希望通过类的实例(无需继承)直接访问类的属性中的属性。所以基本上如果我有: class A: @property def foo(self): print("foo") @property def bar(self): print("bar") class B: def __init__(self): self._a = A() 我希望能够做b.bar,而不是做b.bar。基于此,我在B班尝试了以下方法

我希望通过类的实例(无需继承)直接访问类的属性中的属性。所以基本上如果我有:

class A:
    @property
    def foo(self):
        print("foo")
    @property
    def bar(self):
        print("bar")

class B:
    def __init__(self):
        self._a = A()
我希望能够做
b.bar
,而不是做
b.bar
。基于此,我在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
  • 为什么在创建实例时同时打印“foo”和“bar”
  • “foo”属性如何指向与“bar”相同的getter

  • 创建实例时会打印
    bar
    foo
    ,因为执行
    \u a.\u getattribue\u(“foo”)
    \u a.foo
    都会调用属性对象以获取值

    B
    中设置的两个属性都使用lambdas从
    A
    获取正确的
    属性。这是调用lambdas时的常见错误。由于
    attr
    值是从外部范围继承的,因此在计算lambda时不会冻结该值。相反,它只是与封闭范围的
    attr
    引用相同的
    attr
    ,并相应地更改。因此,所有lambda都将具有相同的
    attr

    您可以定义一个方法。当普通属性查找失败时调用此方法

    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
    

    创建实例时会打印
    bar
    foo
    ,因为执行
    \u a.\u getattribue\u(“foo”)
    \u a.foo
    都会调用属性对象以获取值

    B
    中设置的两个属性都使用lambdas从
    A
    获取正确的
    属性。这是调用lambdas时的常见错误。由于
    attr
    值是从外部范围继承的,因此在计算lambda时不会冻结该值。相反,它只是与封闭范围的
    attr
    引用相同的
    attr
    ,并相应地更改。因此,所有lambda都将具有相同的
    attr

    您可以定义一个方法。当普通属性查找失败时调用此方法

    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
    

    你的第二个问题在这里有一个更详细的答案:你的第二个问题在这里有一个更详细的答案:谢谢你的回答和链接到另一个问题!我曾想过定义
    \uu getattr\uuu
    ,但在我看来,它会覆盖标准属性访问器。只有在标准访问器失败时才会调用它,这似乎是合乎逻辑的(至少对我来说是方便的)。与我最初的尝试相比,它最终也是一种更干净的代码。直到lambdas很好,但可能会产生危险的误导…谢谢你的回答和其他问题的链接!我曾想过定义
    \uu getattr\uuu
    ,但在我看来,它会覆盖标准属性访问器。只有在标准访问器失败时才会调用它,这似乎是合乎逻辑的(至少对我来说是方便的)。与我最初的尝试相比,它最终也是一种更干净的代码。直到lambdas很好,但可能会产生危险的误导。。。