Python - Как мне написать более эффективное Pythonic сокращение? - PullRequest
10 голосов
/ 18 марта 2011

Я пытаюсь создать очень легкий класс 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

1 Ответ

5 голосов
/ 18 марта 2011

Я думаю (не проверено), что вам вместо 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, в зависимости от того, что вы используете чаще всего.

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