3

I am using a module that is part of a commercial software API. The good news is there is a python module - the bad news is that its pretty unpythonic.

To iterate over rows, the follwoing syntax is used:

cursor = gp.getcursor(table)
row =  cursor.next()
while row:
    #do something with row
    row = cursor.next()

What is the most pythonic way to deal with this situation? I have considered creating a first class function/generator and wrapping calls to a for loop in it:

def cursor_iterator(cursor):
    row =  cursor.next()
    while row:
        yield row
        row = cursor.next()

[...]

cursor = gp.getcursor(table)
for row in cursor_iterator(cursor):
    # do something with row

This is an improvement, but feels a little clumsy. Is there a more pythonic approach? Should I create a wrapper class around the table type?

4
  • Mmmh cursor.next() looks like you might be able to do for row in cursor: Commented Jun 5, 2010 at 10:56
  • 1
    @Felix, nope. next doesn't raise a StopIteration, so after the real data, that would just loop forever with row being None. Commented Jun 5, 2010 at 11:00
  • @Felix King: Almost, but because an iterator signals termination by raising StopIteration, for row in cursor: will iterate over the rows, then give an infinite stream of Nones. Commented Jun 5, 2010 at 11:00
  • @Matthew, @Paul: Ok :) Thank you, I was not aware of that. Commented Jun 5, 2010 at 11:04

3 Answers 3

11

Assuming that one of Next and next is a typo and they're both the same, you can use the not-so-well-known variant of the built-in iter function:

for row in iter(cursor.next, None):
    <do something>
Sign up to request clarification or add additional context in comments.

1 Comment

Great answer! Yep, the functions are the same (worse still, they are somehow case insensitive!).
2

You could create a custom wrapper like:

class Table(object):
    def __init__(self, gp, table):
        self.gp = gp
        self.table = table
        self.cursor = None

   def __iter__(self):
        self.cursor = self.gp.getcursor(self.table)
        return self

   def next(self):
        n = self.cursor.next()
        if not n:
             raise StopIteration()
        return n

and then:

for row in Table(gp, table)

See also: Iterator Types

1 Comment

I like this approach also. I might consider wrapping gp in this manner if I need to wrap more than just the cursor iteration.
1

The best way is to use a Python iterator interface around the table object, imho:

class Table(object):
    def __init__(self, table):
         self.table = table

    def rows(self):
        cursor = gp.get_cursor(self.table)
        row =  cursor.Next()
        while row:
            yield row
            row = cursor.next()

Now you just call:

my_table = Table(t)
for row in my_table.rows():
     # do stuff with row

It's very readable, in my opinion.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.