python - How to make a class iterable, but not have the iterator modified if you modify the class? -
i new python , coding in general, i'm lost. have coded "node" class (shown below @ bottom) instantiates binary search tree , couple of methods insert(), , elements() (which returns list of elements inorder transversing tree). supposed make class iterable: "iter__(self) should return nodeiterator, returns elements tree in sorted order. modifying tree should not modify existing iterators." i'm trying inserting code class right now:
def __iter__(self): x=self.copy() x.i=0 return x def next(self): lst=x.elements() #??? no idea here.
i defined x=self.copy() try cover fact modifying tree shouldn't modify iterator, don't know if right idea. here node class decorator used in 1 of methods:
def depth(old_f): ''' write decorator overrides standard behavior of function returns true or false , instead returns 0 false or n number of recursive calls needed return true. ''' def new_f(*args): res = old_f(*args) if res true: return 1 elif res: return 1 + res else: return 0 return new_f class node(object): ''' modify node class homework 4 follows: 2 elements compare equal shouldn't allowed in tree. if copy inserted, throw alreadyexistsexception error message "element [x] in tree". __iter__(self) should return nodeiterator, returns elements tree in sorted order. modifying tree should not modify existing iterators. ''' count = 0 def __init__(self, val, left=none, right=none): self.val = val self.left = left self.right = right node.count += 1 def __repr__(self): '''if node has neither left nor right child, return node(val). else, return node(x, val, y), x , y recursive calls return left , right children, respectively. ''' if self.left none , self.right none: return "node({})".format(self.val) else: return "node({}, {}, {})".format(self.left, self.val, self.right) @depth def search(self, element): ''' finds whether given element in tree. returns true if element found, else returns false. give depth decorator defined earlier. ''' if element == self.val: return true elif self.val > element , self.left not none: return self.left.search(element) elif self.val < element , self.right not none: return self.right.search(element) else: return false def insert(self, element): ''' insert element binary search tree rooted @ node. after insertion, return modified node. our implementation allow duplicate nodes. left subtree should contain elements <= current element, , right subtree contain elements > current element. ''' if element <= self.val: if self.left not none: self.left.insert(element) else: self.left = node(element) else: if self.right not none: self.right.insert(element) else: self.right = node(element) return self def elements(self): ''' return list of elements visited in inorder traversal: http://en.wikipedia.org/wiki/tree_traversal note should sorted order if you've inserted elements using defined insert function. ''' if self.left none , self.right none: return [self.val] elif self.left none , self.right not none: return [self.val] + self.right.elements() elif self.left not none , self.right none: return self.left.elements() + [self.val] else: return self.left.elements() + [self.val] + self.right.elements()
don't define next
on class; makes instances iterators (which iterate object directly) when want have iterable not iterator. that, define __iter__
, have return whole new iterator on copy of object.
since you've got elements
method snapshots node
, it's not hard use make snapshotting iterator; there's no point in copying structure because you're iterating in order anyway, , elements
can work (and use less memory on snapshot boot). normally, i'd make __iter__
generator function, e.g.:
def __iter__(self): # python 3 simple version yield self.elements() # python 2 or 3 version x in self.elements(): yield x
but since assignment calls special nodeiterator
class, won't do. that, need make new class (possibly defined inside existing node
class namespace it):
class node(object): ... class nodeiterator(object): def __init__(self, node): self.it = iter(node.elements()) def __iter__(self): return self def next(self): return next(self.it) __next__ = next # makes code work on py2 , py3 without modification def __iter__(self): return nodeiterator(self)
you can see why wouldn't bother special class when generator functions __iter__
(functions using yield
magic) simpler, that's basic structure. can read more iterators on python wiki, or basic interfaces on python collections
abc documentation.
Comments
Post a Comment