20

I wrote a function to create the VALUES part of a SQL query:

def query_values(data_iterator):
    return ',\n'.join('\n({})\n'.format(',\n'.join('"{}"'.format(value) for value in data_row)
                                     ) for data_row in data_iterator
                      ),

When I call this function and print the result, I get is:

query_values:
('\n("801",\n"printer",\n"barcode printer")\n,\n\n("844",\n"laptop",\n"windows")\n,\n\n("997",\n"printer",\n"barcode printer")\n',)

All in one line. Instead of breaking the line, the \n are displayed.

Originally I had one \n, but then I inserted multiple, just to see if they would get displayed.

The second problem was that there are parentheses around the entire thing, which I didn't want.

I was puzzling over the two issues, and I figured the solution for the second one:

I had a comma at the end of the function. The comma caused the function to return a tuple, instead of a single string.

I removed the comma:

def query_values(data_iterator):
    return ',\n'.join('\n({})\n'.format(',\n'.join('"{}"'.format(value) for value in data_row)
                                     ) for data_row in data_iterator
                      )

and that fixed both problems. The output was now:

query_values:

("801",
"printer",
"barcode printer")
,

("844",
"laptop",
"windows")
,

("997",
"printer",
"barcode printer")

I put the comma back, and the \n were displayed. I removed the comma, and I have multiple lines again.

I have removed extraneous \n, so now I get what I wanted:

query_values:

("801","printer","barcode printer"),
("844","laptop","windows"),
("997","printer","barcode printer")

So, my code works correctly, but I'm totally confused about the \n characters displayed in the old version of the code. Why was that happening?

UPDATE: A couple answers to this question focused on why I was getting a tuple. That's not my question. Why are /n displayed?

Solomon Ucko
  • 5,724
  • 3
  • 24
  • 45
Granny Aching
  • 1,295
  • 12
  • 37

4 Answers4

19

It seems that this is the behavior of tuples. When a tuple is printed, print calls __repr()__ on each element. The same is also true for lists.

I tried this:

tup = "xxx\nxx",
lst =["xxx\nxx"]
for t in tup,lst:
    print('t      :', t)
    for s in t:
        print('element:',s)
        print('   repr:',s.__repr__())
    print('---')

and the output is:

t      : ('xxx\nxx',)
element: xxx
xx
   repr: 'xxx\nxx'
---
t      : ['xxx\nxx']
element: xxx
xx
   repr: 'xxx\nxx'
---

So, the same behavior for both tuples and lists.

When we have a string, calling __repr__() doesn't expand \n characters, and puts quotes around it:

s = "xxx\nxx"
print('s           :', s)
print('s.__repr__():', s.__repr__())

outputs:

s           : xxx
xx
s.__repr__(): 'xxx\nxx'

This tuple behavior was mentioned in comments by running.t, interjay and Daniel Roseman, but not in answers, that's why I'm posting this answer.

Granny Aching
  • 1,295
  • 12
  • 37
  • More precisely, `tuple`'s `__repr__` ([which is used if `__str__` is not defined](https://github.com/python/cpython/blob/fc96e5474a7bda1c5dec66420e4467fc9f7ca968/Objects/object.c#L552)) [calls `__repr__` on its elements](https://github.com/python/cpython/blob/fc96e5474a7bda1c5dec66420e4467fc9f7ca968/Objects/tupleobject.c#L298). – Solomon Ucko Mar 19 '19 at 18:58
  • Are you saying tuples don't have `__str__` defined? For a tuple `t`, I tried `t.__str__()`, and I get the same as `t.__repr__()`. I don't know how to check whether `__str__()` is undefined, or defined to be the same as `__repr__` – Granny Aching Mar 19 '19 at 19:51
  • [It is marked as undefined in the C code.](https://github.com/python/cpython/blob/fc96e5474a7bda1c5dec66420e4467fc9f7ca968/Objects/tupleobject.c#L842) I don't think the difference is externally visible, however. – Solomon Ucko Mar 19 '19 at 20:04
  • 1
    @SolomonUcko There's no visible difference _for C types_, because you can't actually look up the true attributes in the type's `struct`. For Python types there is a visible difference. – wizzwizz4 Mar 19 '19 at 20:16
  • @wizzwizz4 Yep. At least in CPython, magic methods on C types show up as `slot wrapper`s. – Solomon Ucko Mar 19 '19 at 20:18
  • And those slot wrappers actually contain magic to make sure that any slots that don't exist are "filled in" where possible, because there's the overhead of an intermediate call _anyway_… – wizzwizz4 Mar 19 '19 at 20:19
12

Writing return something, is the same as return (something,): It returns a tuple containing one element. When you print this, it will show the outer parentheses for the tuple, and the string inside will be printed as its source code representation, i.e. with escape codes and inside quotes.

However, return something simply returns that value, which can then be printed normally.

interjay
  • 107,303
  • 21
  • 270
  • 254
  • 1
    I know why I was getting a tuple. My question is **why were the `\n` displayed**. – Granny Aching Mar 19 '19 at 14:30
  • 7
    @GrannyAching: and you have an answer to your question here. **\n is displayed because you print tuple of string instead of single string** and in case of printing tuples this is the default behaviour. – running.t Mar 19 '19 at 14:36
  • 7
    @GrannyAching Printing a tuple calls `repr` on the elements inside. `repr` gives a representation of the object which is usually similar to how it's displayed in the source code, so for strings will contain quotes and escape codes. – interjay Mar 19 '19 at 14:48
1

It seems that's the behavior for tuples in Python. You can test this with a simpler case like so:

>>> print ("xxx\n\nx",)
('xxx\n\nx',)

Seems like Python helps you with debugging and escapes all the command sequences in strings when printing, so that strings appear the same way they were defined.

It did confuse you though, funny case. :)

Nestor Sokil
  • 2,162
  • 12
  • 28
0

A tuple can be denoted with or without parenthesis, its the comma decides the type.

>>> t = 1, 'a', 'abc'
>>> type(t)
<type 'tuple'>
>>> t
(1, 'a', 'abc')
>>> 

In the above case, you added a trailing comma after the string and python interpreted it as a tuple.

Check this link.

>>> t= 'a',
>>> type(t)
<type 'tuple'>
>>> t
('a',)
>>> t = 'a'
>>> type(t)
<type 'str'>
>>> t
'a'
sanooj
  • 493
  • 5
  • 12