代码之家  ›  专栏  ›  技术社区  ›  Chen A.

使用getattr获取祖父母类的属性

  •  -1
  • Chen A.  · 技术社区  · 7 年前

    我正在尝试访问实例属性( inst_baseA / inst_baseB 的) Base 类的实例 ClassB ,具体取决于实例的属性( self.x 属于B类对象)。

    这是我的代码:

    class Base(object):
        def __init__(self):
            self.inst_baseA = 'base_B'
            self.inst_baseB = 'base_A'
    
    
    class ClassA(object):
        def __init__(self):
            self.node = Base()
    
    
    class ClassB(ClassA):
        def __init__(self):
            super(ClassB, self).__init__()
            self.x = 'base_A'
    

    这是我第一次尝试的:

    >>> b = ClassB()
    >>> getattr(b, 'node.inst_{}'.format(b.x))
    
    Traceback (most recent call last):
      File "<pyshell#26>", line 1, in <module>
        getattr(b, 'node.inst_{}'.format(b.x))
    AttributeError: 'ClassB' object has no attribute 'node.inst_base_A'
    

    如果我连呼getattr,我就能克服这个问题:

    >>> getattr(getattr(b, 'node'), b.x)
    'base_A'
    

    出于好奇 :除了执行 呼吁 getattr ?


    更新:我需要它的原因是我试图: -从祖辈类中获取属性(inst_basea或inst_baseb) -取决于我实例上的属性(x的值)

    所以我的代码实际上是这样的: getattr(self, 'node.{}'.format(self.x)) . 我第一次解释的不对,希望现在能讲得通些。

    2 回复  |  直到 7 年前
        1
  •  2
  •   Aran-Fey Kevin    7 年前

    operator.attrgetter ,但它实际上并不适用于这种情况,因此语法相当尴尬:

    >>> operator.attrgetter('node.inst_base')(b)
    'base'
    

    但这真的很不直观,所以为了避免让阅读您的代码的人感到困惑,最好使用自己的multi getattr:

    def get_multi_attr(obj, attrs):
        for attr in attrs.split('.'):
            obj = getattr(obj, attr)
        return obj
    
    >>> get_multi_attr(b, 'node.inst_base')
    'base'
    
        2
  •  2
  •   CristiFati    7 年前

    根据 [Python]: getattr ( object, name[, default] ) :

    返回的命名属性的值 对象 . 名称 必须是字符串。如果字符串是其中一个对象属性的名称,则结果是该属性的值。例如, getattr(x, 'foobar') 相当于 x.foobar .

    node.inst_base 属性 b 但是,

    • node
    • inst_base b.node

    所以,你需要一个 getattr 调用每个“嵌套”级别。

    考虑到我已经在解释器的交互窗口中粘贴了您的代码:

    >>> getattr(b, 'node.inst_base')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'ClassB' object has no attribute 'node.inst_base'
    >>>
    >>> getattr(getattr(b, "node", None), "inst_base", None)
    'base'
    

    或者,为了更进一步,您可以创建一个使用“嵌套”属性名的getter:

    >>> def getattr_nested(obj, nested_attr):
    ...     attrs = nested_attr.split(".")
    ...     ret = obj
    ...     for attr in attrs:
    ...             ret = getattr(ret, attr, None)
    ...             if ret is None:
    ...                     return None
    ...     return ret
    ...
    >>>
    >>> getattr_nested(b, "node.inst_base")
    'base'
    >>> getattr_nested(b, "node.inst_base2")
    >>> getattr_nested(b, "node")
    <__main__.Base object at 0x0000021A2A593D30>
    

    但这可能效率很低(而且,也不能处理角落的案子),你最好使用@aran fey的建议。