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

Popular posts from this blog

html - Outlook 2010 Anchor (url/address/link) -

javascript - Why does running this loop 9 times take 100x longer than running it 8 times? -

Getting gateway time-out Rails app with Nginx + Puma running on Digital Ocean -