Может ли понимание списка Python использоваться в этом сценарии использования? - PullRequest
0 голосов
/ 15 мая 2019

Недавно мне пришлось пройти по дереву, начиная с произвольного узла до его корня. Я написал что-то вроде

breadcrumbs = []
while node is not None:
    breadcrumbs.append(node.get_text())
    node = node.get_parent()

Мне пришло в голову, что это выглядит как уродливая реализация построения списка, использующего

result = []
while node is not None:
    result.append(node.get_text())
    node = node.next()

вместо более идиоматического понимания списка

result = [node.get_text() for node in nodes]

Это заставило меня задуматься, есть ли более идиоматический способ построения списка из моего обхода дерева. Для полноты (и поскольку приведенные выше выдержки в основном являются псевдокодом), вот фактический код, который я использовал:

model, treeiter = self.treeview.get_selection().get_selected()
breadcrumbs = []
while treeiter is not None:
    breadcrumbs.append(model.get_value(treeiter, self.COL_TEXT))
    treeiter = model.iter_parent(treeiter)
path = '/'.join(reversed(breadcrumbs))

Для контекста первая строка вызывает Gtk.TreeSelection.get_selected (одно из возвращаемых значений в API называется iter, но не имеет ничего общего с итераторами Python). Мой код создает строку из пути, выбранного пользователем, например, "A/b/2" в приведенном ниже примере:

+- A
|  |- a
|  \- b
|     |- 1
|     \- 2       <- selected element
\- B
   |- c
   \- d

Ответы [ 2 ]

3 голосов
/ 15 мая 2019

Вы правы, используемая вами древовидная структура не очень питонна.Но вы можете легко превратить его в более питоническое решение, используя самодельные генераторы .

Например, для обхода родителей (или предков) вы можете определить функцию iter_parents, например:это:

def iter_parents(node):
    while node is not None:
        yield node
        node = node.get_parent()

С этим в руке, вы можете построить панировочные сухари, как это:

breadcrumbs = [node.get_text() for node in iter_parents(branch)]

Вот небольшая демонстрация:

class Node(object):
    def __init__(self, text, parent=None):
        self._text = text
        self._parent = parent

    def get_text(self):
        return self._text

    def get_parent(self):
        return self._parent


branch = Node("c", Node("b", Node("a")))

breadcrumbs = [node.get_text() for node in iter_parents(branch)]

print(breadcrumbs)
# -> ['c', 'b', 'a']

Для node.next() Вы можете определить генератор iter_next() таким же образом.

edit

Используйте reverse, чтобы перевернуть список, например:

breadcrumbs = [node.get_text() for node in iter_parents(branch)]
breadcrumbs.reverse()

print(breadcrumbs)
# -> ['a', 'b', 'c']
0 голосов
/ 15 мая 2019

Конечно, вы можете обернуть свой цикл while в генераторе следующим образом:

def get_parents(node):
    while node is not None:
        yield node
        node.get_parent()

Тогда вы можете использовать:

result = [node.get_text() for node in get_parents(nodes)]
...