在python中編寫一個樹類的迭代器時,我偶然發現了這個問題,我顯然無法訪問母類的字段和方法,而沒有實例化引用已存在的樹實例的迭代器實例,所以我總是需要調用像it.iterate(tree)這樣非常醜陋的迭代器。我想知道是否有某種方法來設計這個東西,所以不需要迭代器及其方法的實例引用。所以,我可以以某種方式從Iterator的實例訪問Tree實例的字段,而無需將Tree實例的引用傳遞給迭代器?Python訪問母類字段
########################################################################
# basic tree class, can be traversed bottom up from right hand corner
########################################################################
import sys
########################################################################
########################################################################
class Node:
"""!
@brief node class
"""
def __init__(self, pred=-1, ID=0, label=None):
self.sucs = list()
self.pred = pred
self.ID = ID
self.suc_count = 0
self.label = label
########################################################################
def make_suc(self, ID, label=None):
"""!
@brief generates new successor node, assigning it a unique ID
"""
self.suc_count += 1
sucID = ID+1
suc = Node(self, sucID, label)
self.sucs.append(suc)
return suc
########################################################################
########################################################################
class Tree:
"""!
@brief tree class
"""
def __init__(self):
self.root = Node()
self.allNodes = dict() # mapping from IDs (strings) to nodes
self.init()
self.leaves = list()
########################################################################
# initializes node dict
def init(self):
self.allNodes[0] = self.root
########################################################################
def find_node(self, ID):
"""!
@brief looks up a node's ID and returns the node itself
"""
return self.allNodes[ID]
########################################################################
def add(self, parent, label=None):
"""!
@brief adds a new node under parent with label label
"""
if parent != Node:
parent = self.find_node(parent)
suc = parent.make_suc(len(self.allNodes)-1, label)
self.allNodes[suc.ID] = suc
########################################################################
def traverse(self, node):
"""!
@brief traverses tree
"""
for suc in node.sucs:
self.traverse(suc)
print suc.label
########################################################################
def get_leaves(self, node):
"""!
@brief when called resets leveas field and build it up anew by
traversing tree and adding all leaves to it
"""
self.leaves = list()
self._find_leaves(node)
return self.leaves
########################################################################
def get_dominated(self, node, dom_nodes=[]):
"""!
@brief finds all dominated nodes
"""
for suc in node.sucs:
self.get_dominated(suc, dom_nodes)
dom_nodes.append(suc)
########################################################################
def _find_leaves(self, node):
"""!
@brief traverses tree in in order and adds all leaves to leaves field
last leaf in list will be right hand corner of tree, due to in
order travsersal
"""
if node.suc_count == 0:
self.leaves.append(node)
for suc in node.sucs:
self._find_leaves(suc)
########################################################################
class TreeRHCIterator:
"""!
@brief Right hand corner initialised iterator, traverses tree bottom
up, right to left
"""
def __init__(self, tree):
self.current = tree.get_leaves(tree.root)[-1] # last leaf is right corner
self.csi = len(self.current.sucs)-1 # right most index of sucs
self.visited = list() # visisted nodes
########################################################################
def begin(self, tree):
return tree.get_leaves(tree.root)[-1]
########################################################################
def end(self, tree):
return tree.root
########################################################################
def find_unvisited(self, node, tree):
"""!
@brief finds rightmost unvisited node transitively dominated by node
"""
leaves = tree.get_leaves(tree.root)
# loop through leaves from right to left, as leaves are listed
# in order, thus rightmost list elememt is rightmost leaf
for i in range(len(leaves)-1, -1, -1):
# return the first leaf, that has not been visited yet
if leaves[i] not in self.visited:
return leaves[i]
# return None if all leaves have been visited
return None
########################################################################
def go_up(self, node, tree):
"""!
@brief sets self.current to pred of self.current,
appends current node to visited nodes, reassignes csi
"""
self.visited.append(self.current)
self.current = self.current.pred
if self.current.sucs[0] not in self.visited:
self.current = self.find_unvisited(self.current, tree)
self.csi = len(self.current.sucs)-1
self.visited.append(self.current)
########################################################################
def iterate(self, tree):
"""!
@brief advances iterator
"""
# if current node is a leaf, go to its predecessor
if self.current.suc_count == 0 or self.current in self.visited:
self.go_up(self.current, tree)
# if current node is not a leaf, find the next unvisited
else:
self.current = self.find_unvisited(self.current, tree)
########################################################################
########################################################################
這樣調用:
tree = Tree()
it = tree.TreeRHCIterator(tree)
end = it.end(tree)
while (it.current != end):
print it.current.label
it.iterate(tree)
編輯
實現標準迭代器協議,我關於它的工作原理有點糊塗了。不知何故,當循環播放樹時,開始節點會被跳過。所以我做了一個測試課來研究行爲,即使迭代方法基本上以相同的方式工作,也沒有元素被跳過。有人能幫我解釋一下嗎?
重新設計的迭代器:
########################################################################
# RIGHT-HAND-CORNER-BOTTOM-UP-POST-ORDER-TRAVERSAL-ITERATOR
########################################################################
class RBPIter:
"""!
@brief Right hand corner initialised iterator, traverses tree bottom
up, right to left
"""
def __init__(self, tree):
self.current = tree.get_leaves(tree.root)[-1] # last leaf is right corner
self.csi = len(self.current.sucs)-1 # right most index of sucs
self.visited = list() # visisted nodes
self.tree = tree
self.label = self.current.label
########################################################################
def __iter__(self):
print "iter: ", self.label
return self
########################################################################
def begin(self):
return self.tree.get_leaves(self.tree.root)[-1]
########################################################################
def end(self):
return self.tree.root
########################################################################
def find_unvisited(self, node):
"""!
@brief finds rightmost unvisited node transitively dominated by node
"""
leaves = self.tree.get_leaves(self.tree.root)
# loop through leaves from right to left, as leaves are listed
# in order, thus rightmost list elememt is rightmost leaf
for i in range(len(leaves)-1, -1, -1):
# return the first leaf, that has not been visited yet
if leaves[i] not in self.visited:
self.label = leaves[i].label
return leaves[i]
# return None if all leaves have been visited
return None
########################################################################
def go_up(self, node):
"""!
@brief sets self.current to pred of self.current,
appends current node to visited nodes, reassignes csi
"""
self.visited.append(self.current)
self.current = self.current.pred
if self.current.sucs[0] not in self.visited:
self.current = self.find_unvisited(self.current)
self.label = self.current.label
self.csi = len(self.current.sucs)-1
self.visited.append(self.current)
########################################################################
def next(self):
"""!
@brief advances iterator
"""
print "next: ", self.label
# if current node is a leaf, go to its predecessor
if self.current.suc_count == 0 or self.current in self.visited:
self.go_up(self.current)
# if current node is not a leaf, find the next unvisited
else:
self.current = self.find_unvisited(self.current)
if self.current == self.end():
raise StopIteration
return self
########################################################################
########################################################################
對於下面的測試文件,我得到了下面的輸出:
tree1 = Tree()
tree1.add(0, "t")
tree1.add(1, "e")
tree1.add(2, "s")
tree1.add(3, "t")
tree1.add(2, "t")
tree1.add(5, "r")
tree1.add(6, "i")
tree1.add(7, "s")
tree1.add(6, "a")
for node in tree1.RBPIter(tree1):
print node.label
輸出:
iter: a
next: a
s
next: s
i
next: i
r
next: r
t
next: t
t
next: t
s
next: s
e
next: e
t
next: t
樹,這看起來是這樣的:
!因此,正如你所看到的,「a」 - 意味着右手角落節點缺失,我不明白爲什麼,因爲迭代器方法正確返回第一個元素,就像你可以請參閱調試輸出。
你爲什麼不使用普通的迭代器協議:
與調用它?實現'__iter__'? – thefourtheye
以前不知道。但是,我也許想爲不同的遍歷命令使用不同的迭代器。 –
對於這個問題,爲什麼不用'self_tree = tree'在'__init__'中存儲'tree'對象? – thefourtheye