Подтвердить что ты не робот

Python - Как написать более эффективный, Pythonic сокращение?

Я пытаюсь создать очень легкий класс Node, который будет служить инструментом поиска иерархии на основе Python. См. Определение ниже.

from functools import reduce
from operator import or_


class Node:

    def __init__(self, name):
        self.name = name
        self.children = []

    def add_child(self, child_node):
        self.children.append(child_node)

    def contains(self, other_node):
        if self == other_node:
            return True
        elif other_node in self.children:
            return True
        else:
            return reduce(or_, [child.contains(other_node)
                                for child in self.children], False)

    def is_contained_by(self, other_node):
        return other_node.contains(self)

    def __eq__(self, other_node):
        return self.name == other_node.name

    def __de__(self, other_node):
        return self.name != other_node.name

contains представляется учебным случаем функционального программирования (вытаскивается непосредственно из Почему вопросы функционального программирования).

Вопрос: существует ли более эффективный или питонический способ написания contains? Я знаю, что map обычно заменяется пониманием списка, но я не видел лучшего способа сделать рекурсию на основе reduce.

Спасибо,

Mike

=== ИЗМЕНИТЬ... ЗДЕСЬ КРАТНЫЙ КЛАСС, УЧИТЫВАЯ ОТВЕТ И КОММЕНТАРИИ ===

class Node:

    def __init__(self, name):
        self.name = name
        self.children = []

    def add_child(self, child_node):
        # Hattip to lazyr for catching this.
        if self.contains(child_node) or child_node.contains(self):
            raise TreeError('A relationship is already defined.')    
        else:
            self.children.append(child_node)                

    def contains(self, other_node):
        # Hattip to lazyr for pointing out any() and to Jochen Ritzel for
        # eliminating the silly child check.
        return (self == other_node or
                any(child.contains(other_node) for child in self.children))

    def is_contained_by(self, other_node):
        return other_node.contains(self)

    def __eq__(self, other_node):
        return self.name == other_node.name

    def __de__(self, other_node):
        return self.name != other_node.name

    def __repr__(self):
        return self.name
4b9b3361

Ответ 1

Я думаю (не тестировался), что вместо reduce следует использовать any, как это, что остановится при первом ударе:

return any(child.contains(other_node) for child in self.children)

Кстати, вы имели в виду a.contains(b) для возврата False, когда a == b и len(a.children) > 0?

Изменить. Если ваше дерево содержит цикл, например:

a = Node("a")
b = Node("b")
a.add_child(a)
a.add_child(b)

то

a.contains(b)

приведет к сбою программы. Вы можете проверить это либо в contains, либо в add_child, в зависимости от того, какой вы используете больше всего.