Получение атрибута класса дедушки с помощью getattr - PullRequest
0 голосов
/ 06 июня 2018

Я пытаюсь получить доступ к атрибуту экземпляра (inst_baseA / inst_baseB) класса Base из экземпляра ClassB, в зависимости от атрибута экземпляра (self.x объекта ClassB).

Вот мой код:

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 ]

0 голосов
/ 06 июня 2018

Есть operator.attrgetter, но на самом деле он не предназначен для такого рода вещей, поэтому синтаксис довольно неловкий:

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

Но это действительно довольно не интуитивно понятно, так чтово избежание путаницы с людьми, которые читают ваш код, лучше вместо этого использовать собственный мульти-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'
0 голосов
/ 06 июня 2018

Согласно [Python]: getattr ( объект, имя [, по умолчанию] ) :

Вернуть значениеименованного атрибута объекта . имя должно быть строкой.Если строка является именем одного из атрибутов объекта, результатом является значение этого атрибута.Например, getattr(x, 'foobar') эквивалентно x.foobar.

node.inst_base является , а не атрибутом b, но:

  • node является атрибутом b
  • 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'

Или, если пойти дальше, вы можете создать геттер, который работает с«вложенные» имена атрибутов:

>>> 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...