17

I was testing some code on the interpreter and I noticed some unexpected behavior for the sqlite3.Row class.

My understanding was that print obj will always get the same result as print str(obj), and typing obj into the interpreter will get the same result as print repr(obj), however this is not the case for sqlite3.Row:

>>> print row       # the row object prints like a tuple
(u'string',)
>>> print str(row)  # why wouldn't this match the output from above?
<sqlite3.Row object at 0xa19a450>

>>> row             # usually this would be the repr for an object
(u'string',)
>>> print repr(row) # but repr(row) is something different as well!
<sqlite3.Row object at 0xa19a450>

I think sqlite3.Row must be a subclass of tuple, but I still don't understand exactly what is going on behind the scenes that could cause this behavior. Can anyone explain this?

This was tested on Python 2.5.1, not sure if the behavior is the same for other Python versions.

Not sure whether or not this matters, but the row_factory attribute for my Connection was set to sqlite3.Row.

Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
  • Did you look at http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python before posting? – ktdrv Oct 27 '11 at 18:11
  • @kaloyan - I can't find anything there that answers my question, if you can please point me to it. – Andrew Clark Oct 27 '11 at 18:17
  • Interesting behaviour. `sqlite3.Row` doesn't seem to subclass tuple, so my guess is the print statement special-cases lists and/or tuples based on some other criteria than inheritance, but I can't find anything in the documentation that would admit, much less explain this. – millimoose Oct 27 '11 at 18:27

2 Answers2

12

PySqlite provides the special native hook for print, but it doesn't implement __repr__ or __str__. I'd say that's a bit of a missed chance, but at least it explains the behavior you're observing.

See pysqlite source: https://github.com/ghaering/pysqlite/blob/master/src/row.c#L241 And python docs: http://docs.python.org/c-api/typeobj.html#tp_print

Ondergetekende
  • 1,065
  • 9
  • 22
  • 2
    Nice find! It appears that the sqlite developers went against the recommendations which is probably why this isn't seen in more places. From the docs: "A type should never implement tp_print in a way that produces different output than tp_repr or tp_str would" and "it is recommended not to define tp_print, but instead to rely on tp_repr and tp_str for printing". – Andrew Clark Oct 27 '11 at 19:15
  • 3
    I've linked this topic in pysqlite's bugtracker: http://code.google.com/p/pysqlite/issues/detail?id=4 – Ondergetekende Oct 27 '11 at 19:22
  • @Ondergetekende the bug link broke, did it end up somewhere else, or shall we open a new one (at http://bugs.python.org/ ? ) – Ciro Santilli OurBigBook.com Dec 11 '15 at 17:30
  • 1
    @CiroSantilli I've updated my answer to account for the migration to github. The poor functionality still isn't resolved though – Ondergetekende Mar 09 '17 at 12:42
0
s = str(tuple(row))

is a workaround if you want the original tuple string representation.

It is useful for example if you want to log the row easily as in:

logging.debug(tuple(user_row))

Works because rows are iterable.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985