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
Ответы
Ответ 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
, в зависимости от того, какой вы используете больше всего.