0

There is already a question about checking whether an object is iterable, but sometimes I need to glimpse into what the iterable object looks like. For example, I found on SO that I can do the following:

sqlite_cursor.execute('SELECT * FROM mytable')
csv_writer.writerows(sqlite_cursor)

This works, but I cannot fathom how I could come up with this solution by myself without peeking into the db_cursor object to determine whether it is a list of list (so that I can be given to writerows()).

How do I peek into the object like that?

Community
  • 1
  • 1
Heisenberg
  • 8,386
  • 12
  • 53
  • 102
  • 1
    What if you try iterating it? – Lasse V. Karlsen Jul 01 '14 at 14:59
  • 3
    A SQL query result is **always** a list of lists. It would **never** yield a single value. **There is no problem here**. – Martijn Pieters Jul 01 '14 at 15:00
  • @LasseV.Karlsen a only clean way I know in `pdb` is do `[x for x in sqlite_cursor]`. That does iterate through but the structure of the object (list of lists) is not immediately. Is there a better way to see the structure? – Heisenberg Jul 01 '14 at 15:03
  • @Anh: You can grab the first row with `next(sqlite_cursor)`. However, a SQL cursor **by definition** will always yield rows when iterated.. – Martijn Pieters Jul 01 '14 at 15:05
  • @MartijnPieters the code works, but I'm asking from the perspective of a learner who does not know that fact and need to peek into the object to discover it. Plus, the question generalizes to other objects returned by some custom modules that we have not seen before for example. – Heisenberg Jul 01 '14 at 15:05
  • @alecxe: I downvoted because *there is no issue here*. There is no need to use `fetchall()` instead. Even if there was a possibility that the iterable yields lists sometimes, scalar values at other times, then you'd not need to load the whole thing in memory first. You'd use `next()` to look at the first result, then decide on `writerow()` or `writerows()` after that. – Martijn Pieters Jul 01 '14 at 15:06
  • @Anh: APIs that return lists one moment, single values the next are few and far between. `re.findall()` is the only one I can think of right now. That's because they are kind of broken. – Martijn Pieters Jul 01 '14 at 15:07
  • @Anh: For debugging purposes, use `next()` to look at what the next value in an iterable is. You can then use `csv.writerow()` to write that first result. Take into account it'll raise `StopIteration` if there are no result at all. – Martijn Pieters Jul 01 '14 at 15:08
  • @Anh: In any case, you picked a bad example. You'd check the documented behaviour, even as a learner. Even for single-column results, cursors always return rows as a container (a sequence like a list or tuple, or optionally, some database adapters will give you a dictionary). – Martijn Pieters Jul 01 '14 at 15:11
  • @MartijnPieters I found `next()` to be an useful debugging tool. Could you please turn it into an answer since the comment thread is now quite long? I'm still not sure what to do as learner however. the `csv` docs is clear that `writerows()` take list of lists -- however I have been searching in the `sqlite` doc with no firm statement that `SELECT` also returns the same. (I trust you, I just wonder what's the best way to figure it out by myself). – Heisenberg Jul 01 '14 at 15:16
  • @MartijnPieters I guess I'm coming from `R` language, in which I can do `str(object)` to view its structure very clearly (list of lists, list of vectors, etc.) – Heisenberg Jul 01 '14 at 15:18
  • @Anh: an iterator is not a list of lists though. It is an opaque object that produces new values on demand. If you wanted a list of lists, then do what Alecxe told you: use `cursor.fetchall()` to retrieve all results into a big list. But that wasn't what your question appeared to be about. – Martijn Pieters Jul 01 '14 at 15:20
  • @MartijnPieters you're right, an iterator is not necessarily a list of lists. I'm asking how do I determine that in this particular case, a SQL query result, is a list of lists? Can't I inspect the object instead of looking at the docs? – Heisenberg Jul 01 '14 at 15:30
  • 1
    @Anh: You'd look at the documentation. The [Python DB-API spec](http://legacy.python.org/dev/peps/pep-0249/) states that `Cursor.next()` (part of the iterator protocol) acts just like `Cursor.fetchone()` unless there are no more rows. If there is a row to fetch, `cursor.fetchone()` returns a row, always. – Martijn Pieters Jul 01 '14 at 15:33
  • 1
    I don't think this has anything to do with the database API. That's just the example the OP is using to illustrate his basic question: "How do I check the content of iterable object?" – Jamie Cockburn Jul 01 '14 at 16:08

1 Answers1

1

Here's the idiom I use if I want to peak at an iterable in python:

import itertools

peek = iterable.next()
iterable = itertools.chain([peek], iterable)

You could make a function of it like this:

def peek(iterable):
    peek = iterable.next()
    return peek, itertools.chain([peek], iterable)

And use is like this:

iterable = iter([1,2,3])
peek, iterable = peek(iterable)
print "peek: %s" % peek
print "iterable: %s " % list(iterable)

Output:

peek: 1
iterable: [1, 2, 3]
Jamie Cockburn
  • 7,379
  • 1
  • 24
  • 37
  • Thanks for your help! I'm parsing RSS feeds, so when I `peek` I couldn't immediately see that the element itself is a list due to all the html tags and long text. Do you then recommend that I `peek` again? I'm just trying to figure out the best way to investigate the structure of a complex objects. – Heisenberg Jul 01 '14 at 17:05
  • @Anh that sounds like some sort of deeply nested data you've got. You should probably start a new question, with your specific problem, as I think it's a to deep a conversion for the comment thread. – Jamie Cockburn Jul 01 '14 at 17:16