9

can anyone enlighten me on the differences between print sth and print str(sth) ?

E.g. in the example from the official documentation for sqlite3, one can currently see the following code that creates a database and then uses a factory class to wrap data extracted from there:

(1) Create a database:

# I am using CPython 2.7, but I suppose 2.6 will be Ok as well
import sqlite3
conn = sqlite3.connect(":memory:")
c = conn.cursor()

c.execute('''create table stocks
(date text, trans text, symbol text, qty real, price real)''')
c.execute("""insert into stocks values ('2006-01-05','BUY','RHAT',100,35.14)""")
conn.commit()

c.close()

(2) Now using the Row factory to produce some objects:

>>> conn.row_factory = sqlite3.Row
>>> c = conn.cursor()

>>> c.execute('select * from stocks')
<sqlite3.Cursor object at 0x7f4e7dd8fa80>
>>> r = c.fetchone()
>>> type(r)
<type 'sqlite3.Row'>
>>> r
(u'2006-01-05', u'BUY', u'RHAT', 100.0, 35.14)

As you see, we can type r, or print r to get this nice representation of the row object.

But what is not shown above, it is that print str(r) will give you something different -- something more like:

<sqlite3.Row object at 0x7f4e7dd8abcd> 

So I wonder if someone well-acquainted with CPython implementation can explain what print does to obtain this kind of representation from an object that does not support __str__ ?

Or I guess an alternative question would be -- in the case when the above expressions give different results -- how I can obtain a string equivalent to the one that would be printed with simple print obj ?

ジョージ
  • 1,476
  • 1
  • 22
  • 29
  • Possible duplicate of [How can printing an object result in different output than both str() and repr()?](http://stackoverflow.com/questions/7920284/how-can-printing-an-object-result-in-different-output-than-both-str-and-repr) – Ciro Santilli OurBigBook.com Dec 11 '15 at 17:09
  • @CiroSantilli华涌低端人口六四事件法轮功 : good point. Although -- though I am certainly biased -- I like my answer better. PS: ["how I learned to stop worrying and love the dupes"](https://stackoverflow.blog/2010/11/16/dr-strangedupe-or-how-i-learned-to-stop-worrying-and-love-duplication/) – ジョージ Feb 06 '18 at 10:30
  • Copy your answer there, modify one line to avoid dupe answer moderators, and let's close this :-) – Ciro Santilli OurBigBook.com Feb 06 '18 at 10:48

2 Answers2

7

While I was writing this and looking for some references, I have actually found the most part of the answer:

  1. the C implementation for a Python object may implement PyObject_Print() function, which defines the way the object will be printed to a file, including stdout;

  2. So to get that representation, one should probably use the cStringIO module (didn't try that yet, but supposedly this should work).

Nevertheless, I will leave this question here in a hope that someone may find it useful -- or provide a better answer.

Upd. A cStringIO example:

import cStringIO as C; s = C.StringIO(); print >>s, r, ; s.getvalue()  

-- the last comma helps to get rid of the newline character(s) [ what I suppose depends on the platform ]

PS. Couple of somewhat related questions here on SO:
-- "Python print isn't using __repr__, __unicode__ or __str__ for unicode subclass?"
-- "Difference between __str__ and __repr__ in Python?"

( For example, the first question's answer answer has this nice link to the code of PyFile_WriteObject() . )

PPS. In py3k, this discrepancy seems to be gone completely.

Community
  • 1
  • 1
ジョージ
  • 1,476
  • 1
  • 22
  • 29
3

This is the difference between __str__ and __repr__

Both methods will return a string representing the object, but:

  • __repr__ should return a valid Python expresion or something like <....> if it can't produce that
  • __str__ could return a more user friendly string

Formally, print sth if the same as print repr(sth):

>>> class C:
...   def __str__(self):
...     return "__str__"
...   def __repr__(self):
...     return "__repr__"
... 
>>> c = C()
>>> c
__repr__
>>> print c
__str__
>>> `c`
'__repr__'
>>> repr(c)
'__repr__'
>>> str(c)
'__str__'

Concerning the print statement, If an object is not a string, it is first converted to a string using the rules for string conversions and concerning string conversion rules : The built-in function repr() performs exactly the same conversion in its argument as enclosing it in parentheses and reverse quotes does. The built-in function str() performs a similar but more user-friendly conversion.


EDIT: Concerning the specific case cited as an example, it appears that at C-level sqlite3.row defines PyTypeObject.tp_print as a pointer to a custom printing function that forwards to PyTuple_Type.tp_print. In the same time, tp_str and tp_repr are left undefined -- an so will fallback to the default object print behavior as observed.

As a conclusion, with python 2.x, print(obj), print(str(obj)) and print(repr(obj)) have the potential to produce three different results.

This discrepancy seems to have been lifted in 3.x as the print statement became a normal function.

# In Python 3.3:
>>> print(r)
<sqlite3.Row object at 0x7f4cedfbffd0>
>>> print(repr(r))
<sqlite3.Row object at 0x7f4cedfbffd0>
>>> print(str(r))
<sqlite3.Row object at 0x7f4cedfbffd0>

EDIT2: Still concerning the specific case of sqlite3.Row, it appears that a row could be converted to a tuple. I have tested it both with Python 2.6 and 3.3.

Python 2.6:

>>> sys.version
'2.6.6 (r266:84292, Dec 26 2010, 22:31:48) \n[GCC 4.4.5]'
>>> type(r)
<type 'sqlite3.Row'>
>>> r
(u'2006-01-05', u'BUY', u'RHAT', 100.0, 35.140000000000001)
>>> tuple(r)
(u'2006-01-05', u'BUY', u'RHAT', 100.0, 35.140000000000001)
>>> repr(tuple(r))
"(u'2006-01-05', u'BUY', u'RHAT', 100.0, 35.140000000000001)"

Python 3.3:

>>> sys.version
'3.3.1 (default, May 28 2013, 18:34:21) \n[GCC 4.4.5]'
>>> type(r)
<type 'sqlite3.Row'>
>>> r
<sqlite3.Row object at 0x7f4cedfbffd0>
>>> tuple(r)
('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14)
>>> repr(tuple(r))
"('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14)"
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
  • 1
    "Formally, `print sth` if the same as `print str(sth)`" (there is an obvious typo in your text, 'str' <-> 'repr') That's exactly what was my understanding of the subject before I have noticed that e.g. for the code from the question, neither the `str()` nor the `repr()` functions won't produce the same result as `c = cStringIO.StringIO(); print >>c ... ; c.getvalue()` – ジョージ Jun 04 '13 at 10:29
  • As you noticed the `PyObject_Print()` function allow native objects to implement their own _print behavior_ without relying on repr/str. My opinion is that it is somewhat a bad idea since it does not allow one to easily get that value back in a variable. Or am I missing something? – Sylvain Leroux Jun 04 '13 at 11:22
  • I tend to agree. But my question was more about how things are implemented than on how they should have been (and, repeat, that was a bit of a surprise, as I also thought `print` and `print str` are more or less equivalent). – ジョージ Jun 04 '13 at 11:30
  • 1
    Having tested it, this behavior has been removed in Python 3.3 (presumably any Python 3.x). `print(r)` display the same thing as `print(repr(r))`. This is probably due to the fact that `print` is now a function an no longer a special language construct. – Sylvain Leroux Jun 04 '13 at 11:34
  • I absolutely agree that ["there should be .. preferably one way to do it"](http://www.python.org/dev/peps/pep-0020/), although -- as a side note -- the print statement is the thing I will be missing the most in py3k, and I can not understand why this _function_ can not also be a _statement_ as well. But that's a completely different thing, I guess. – ジョージ Jun 04 '13 at 12:00
  • If `>>s` causes output to go to `s` rather than `stdout`, would `< – JAB Jun 04 '13 at 12:02
  • @ジョージ Personally, I find `print()` a lot easier to work with than `print`. Here's the rationale for why the statement version was removed, by the way: http://www.python.org/dev/peps/pep-3105/#rationale – JAB Jun 04 '13 at 12:04
  • @JAB I think it is a `print` thing, not a C++ - alike general convention; besides, I guess it was removed in Python 3.* – ジョージ Jun 04 '13 at 12:06
  • @JAB Basically, they want me to enter two extra characters every time I'm debugging something, and it was not like that before Ж:-) – ジョージ Jun 04 '13 at 12:07
  • @ジョージ Indeed, the current equivalent would be `print(*stringargs, file=s)`. And it's not two extra, it's only one (or none if you're using a text editor that supports automatic insertion of closing parentheses/braces/brackets/etc.). ...I'm not sure why the PEP says there's no equivalent to the old `softspace` feature, either. doesn't `print('s', end='')` perform a similar purpose? – JAB Jun 04 '13 at 12:09
  • @SylvainLeroux: I think it should be `print(str(r))`, not `print(repr(r))` ; ( I guess this is an unintentional typo, but I'll leave this comment for those who'd be reading that later -- just in an attempt to avoid some confusion ) – ジョージ Jun 04 '13 at 12:10
  • 1
    Not sure this is your question, but all the magic regarding _pretty formatting_ of `sqlite3.row` while using `print` happens here I think: http://hg.python.org/cpython/file/e9d0fb934b46/Modules/_sqlite/row.c#l162 – Sylvain Leroux Jun 04 '13 at 13:05
  • 1
    @SylvainLeroux: yep, and then it is filled as an entry in the PyTypeObject structure: http://hg.python.org/cpython/file/e9d0fb934b46/Modules/_sqlite/row.c#l215 ; as for the code for printing of the object in 3.* -- it seems that now it is [either `str()` or `repr()`, depending on the flags](http://hg.python.org/cpython/file/tip/Objects/fileobject.c#l140) ( I didn't find easily any Python docs specifying how to control these flags from Python, so I assume it is always `str()` or `repr()` by default ) – ジョージ Jun 05 '13 at 05:26
  • 1
    @ジョージ According to the doc, on 2.7, [Py_PRINT_RAW is the only acceptable flag](http://docs.python.org/release/2.7/c-api/typeobj.html#tp_print) while calling `PyTypeObject.tp_print`. Amusing enough, in 3.x `PyFile_WriteObject` has the [same restriction](http://docs.python.org/release/3.2.5/c-api/file.html#PyFile_WriteObject). I can't see how [the corresponding test](http://hg.python.org/cpython/file/tip/Objects/fileobject.c#l140) could fail? Obviously, it if does (does it?), there are other allowed flags... – Sylvain Leroux Jun 05 '13 at 09:38
  • 1
    ... at least, `Py_PRINT_RAW`is the only _Py_PRINT_ flag defined in Include/object.h: http://hg.python.org/cpython/file/c8212fca8747/Include/object.h#l579 Anyway, I don't think you have the opportunity to control this flag from Python -- except by writing your own C wrapper especially for that purpose. Seems lots of trouble whereas on 2.X the [extended form of the print statement `print ... >>`](http://docs.python.org/2/reference/simple_stmts.html#the-print-statement) should work well enough... – Sylvain Leroux Jun 05 '13 at 09:53
  • 1
    @SylvainLeroux: I think there are just two possibilities for this flag -- either to exist or to be omitted (the latter would be the `else` clause at line 144 ), but it is interesting that the possibility is still there -- I assume it may exist e.g. to support the case where [Container’s __str__ uses contained objects’ __repr__](http://stackoverflow.com/a/2626364/558008). – ジョージ Jun 05 '13 at 10:20
  • @ジョージ That is correct. I didn't read the doc with enough attention :(. The Py_PRINT_RAW _bit_ may either be set or clear => two possibilities. It would be interesting to trace back the code is order to see when `tp_print` is called with that bit set, and when it is called with that bit clear. – Sylvain Leroux Jun 05 '13 at 10:35
  • @ジョージ Please take a look at EDIT2 in my answer ;) May that should be what you were searching at first? – Sylvain Leroux Jun 05 '13 at 10:43
  • @SylvainLeroux: For this case, this is indeed very much cleaner than the `cStringIO` thing ) – ジョージ Jun 06 '13 at 02:09
  • Please put clarifying inofrmation into the answer or the question as appropriate. Comments are hard to follow once they get so big. – George Stocker Jun 06 '13 at 12:08