Python - 如何编写更高效、Pythonic 的 reduce?

10 投票
1 回答
966 浏览
提问于 2025-04-16 13:58

我正在尝试构建一个非常轻量级的节点类,用来作为一个基于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 这个函数看起来是功能编程的经典案例(直接取自 为什么功能编程很重要)。

问题是:有没有更高效或者更符合Python风格的写法来实现 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 个回答

5

我觉得(虽然没测试过)你应该用 any 来代替 reduce,这样可以在找到第一个符合条件的情况下就停止:

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

顺便问一下,你是想让 a.contains(b)a == b 并且 len(a.children) > 0 的时候返回 False 吗?

编辑:如果你的树结构里有个循环,比如这样:

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

那么

a.contains(b)

程序就会崩溃。你可能需要在 contains 或者 add_child 中检查这个问题,具体看你哪个用得更多。

撰写回答