代码之家  ›  专栏  ›  技术社区  ›  Valentin B.

动态创建指向属性属性的属性

  •  0
  • Valentin B.  · 技术社区  · 7 年前

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

    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
    
    1. 为什么创建实例时会同时打印“foo”和“bar”?
    2. “foo”属性如何指向与“bar”相同的getter?
    1 回复  |  直到 7 年前
        1
  •  2
  •   Patrick Haugh    7 年前

    bar foo 在创建实例时打印,因为 _a.__getattribue__("foo") _a.foo 都将调用属性对象以获取值。

    在中设置的两个属性 B 使用lambda获得正确的 property A . 这是一个常见的错误时,调用兰姆达斯。因为 attr 值是从外部作用域继承的,在计算lambda时不会冻结该值。相反,它是完全相同的 阿特尔 作为封闭范围的引用 阿特尔 ,并相应更改。所以你所有的羊羔都要一样的 阿特尔 价值。

    您可以定义 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