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
似乎是函数式编程的教科书案例(直接从 为什么函数式编程很重要)。
问题:有没有更有效或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
I'm trying to build a very lightweight Node class to serve as a Python-based hierarchy search tool. See the definition below.
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
seems to be a textbook case of functional programming (pulled directly from Why Functional Programming Matters).
Question: is there a more efficient or Pythonic way of writing contains
? I know that map
is usually replaced by list comprehension, but I hadn't seen a better way of doing reduce
-based recursion.
Thanks,
Mike
===EDITED ... HERE'S THE REDONE CLASS TAKING INTO ACCOUNT THE ANSWER AND COMMENTS===
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为(未经测试)您应该使用像这样的
any
而不是reduce
,它将在第一次点击时停止:顺便说一句,您的意思是
a.contains(b)
当a == b
且len(a.children) > 时返回
False
0?编辑:如果您的树包含循环,如下所示:
那么
将使程序崩溃。您可能需要在
contains
或add_child
中检查这一点,具体取决于您最常使用的内容。I think (not tested) that you instead of
reduce
should useany
like this, which will stop on the first hit:By the way, did you mean for
a.contains(b)
to returnFalse
whena == b
andlen(a.children) > 0
?Edit: If your tree contains a loop, like this:
then
will crash the program. You may want to check for this either in
contains
or inadd_child
, depending on which you use the most.