Python - 如何编写更高效的Pythonic减少?

时间:2011-03-18 14:53:19

标签: python algorithm graph tree

我正在尝试构建一个非常轻量级的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似乎是函数式编程的教科书案例(直接来自Why Functional Programming Matters)。

问题:是否有更高效或Pythonic的写作方式contains?我知道map通常被列表理解所取代,但我没有看到更好的方法来进行基于reduce的递归。

谢谢,

麦克

===已编辑...这里的重做课程考虑了答案和评论===

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 个答案:

答案 0 :(得分:5)

我认为(未经测试)你代替reduce应该像这样使用any,这将在第一次点击时停止:

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

顺便说一句,您是a.contains(b)Falsea == b时返回len(a.children) > 0的意思吗?

编辑:如果您的树包含循环,请执行以下操作:

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

然后

a.contains(b)

会使程序崩溃。您可能需要在containsadd_child中进行检查,具体取决于您最常使用的内容。