#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2007
    Location
    Joensuu, Finland
    Posts
    428
    Rep Power
    66

    Iterator not iterator when called from another file? [Solved]


    This might be something extremely simple even if I’m not getting it at the moment… I have a small expat XML parser defined as an iterator in kotusparser.py. The file includes a small self-test under “if __name__ == '__main__'“ which calls the iterator; this works flawlessly. However, when imported as a module in another file I’m getting a “TypeError: iter() returned non-iterator of type 'KotusParser'”.

    This is the code for kotusparser.py (with the XML-handling functions removed for brevity):

    Code:
    #!/usr/bin/env python3
    import xml.parsers.expat
    from xml.parsers.expat import ExpatError as ParseError
    
    version = (1, 0, 3)
    
    class KotusParser(object):
        def __init__(self, stream):
            # Public
            self.stream = stream
            self.word = None
            self.paradigm = None
    
            # Implementation details
            # …
    
        def __iter__(self):
            return self
    
        def __next__(self):
            # May raise xml.parsers.expat.ExpatError, handle in caller
            self._xmlparser.Parse(self.stream.__next__())
            return (self.word, self.paradigm)
    
        #
        # Here functions for different XML elements
        #
    
    # Simple test if run as a script
    if __name__ == '__main__':
        import sys
        for arg in sys.argv[1:]:
            with open(arg, 'r') as f:
                for word, paradigm in KotusParser(f):
                    print('{0}:{1}'.format(word, paradigm))
    Run from the command line as “./kotusparser.py somefile.xml” this works.

    However, a test caller containing the very same lines in the simple test above fails (“iter() returned a non-iterator of type 'KotusParser'”):

    Code:
    #!/usr/bin/env python
    import sys
    import kotusparser
    
    for arg in sys.argv[1:]:
        with open(arg, 'r') as f:
            for word, paradigm in KotusParser(f):
                print('{0}:{1}'.format(word, paradigm))
    As I said, I’m not getting it. Is it because kotusparser.py is written explicitly for Python 3 (this usually saves from some nasty Unicode troubles) but the caller file is Python 2 (because the real caller is wxPython and that’s only implemented for Python 2 at the moment)?

    EDIT: That’s really the cause. If the caller has #! line for Python 3, everything works. Now the thing to find out is how to call the iterator as an iterator from Python 2?

    EDIT 2: Found the solution. Python 3 needs __next__(), Python 2 uses next(). If the code is supposed to be run from either major version, you must define next() that simply calls __next__().
    Last edited by SuperOscar; March 24th, 2014 at 02:50 PM. Reason: Found a solution
    My armada: openSUSE 13.1 (home desktop, home laptop), Crunchbang Linux 11 (mini laptop, work laptop), Android 4.2.1 (tablet)
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,703
    Rep Power
    480
    from __future__ import generators


    python -c 'import __future__;help(__future__)'


    Maybe!
    [code]Code tags[/code] are essential for python code and Makefiles!

IMN logo majestic logo threadwatch logo seochat tools logo