53

I have a list L of elements, say natural numbers. I want to print them in one line with a single space as a separator. But I don't want a space after the last element of the list (or before the first).

In Python 2, this can easily be done with the following code. The implementation of the print statement (mysteriously, I must confess) avoids to print an extra space before the newline.

L = [1, 2, 3, 4, 5]
for x in L:
    print x,
print

However, in Python 3 it seems that the (supposedly) equivalent code using the print function produces a space after the last number:

L = [1, 2, 3, 4, 5]
for x in L:
    print(x, end=" ")
print()

Of course there are easy answers to my question. I know I can use string concatenation:

L = [1, 2, 3, 4, 5]
print(" ".join(str(x) for x in L))

This is a quite good solution, but compared to the Python 2 code I find it counter-intuitive and definitely slower. Also, I know I can choose whether to print a space or not myself, like:

L = [1, 2, 3, 4, 5]
for i, x in enumerate(L):
    print(" " if i>0 else "", x, sep="", end="")
print()

but again this is worse than what I had in Python 2.

So, my question is, am I missing something in Python 3? Is the behavior I'm looking for supported by the print function?

Braiam
  • 1
  • 11
  • 47
  • 78
nickie
  • 5,608
  • 2
  • 23
  • 37
  • I think the `join` solution is bad because: (1) it explicitly uses `str`, which I find ugly and counter-intuitive, and most importantly (2) it first constructs a string and then prints it, which may be a bad idea if the list is long. – nickie Mar 21 '14 at 10:46
  • I'm not sure why @Braiam edited the title and removed "in Python 3". The original question, many years ago, was about a difference in practice between Python 2 and Python 3. Anyway... – nickie Aug 08 '21 at 08:46

4 Answers4

148

You can apply the list as separate arguments:

print(*L)

and let print() take care of converting each element to a string. You can, as always, control the separator by setting the sep keyword argument:

>>> L = [1, 2, 3, 4, 5]
>>> print(*L)
1 2 3 4 5
>>> print(*L, sep=', ')
1, 2, 3, 4, 5
>>> print(*L, sep=' -> ')
1 -> 2 -> 3 -> 4 -> 5

Unless you need the joined string for something else, this is the easiest method. Otherwise, use str.join():

joined_string = ' '.join([str(v) for v in L])
print(joined_string)
# do other things with joined_string

Note that this requires manual conversion to strings for any non-string values in L!

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • This answers my question and is actually faster in Python 3 than the `for` loop. I'm puzzled, however, because in Python 3 this takes 2.5 sec. to print `list(range(1000000))`, whereas the original Python 2 `for` loop takes 0.36 sec. Did printing degrade so much in Python3? – nickie Mar 21 '14 at 11:09
  • @nickie: Did you include the `list()` call in your timings? It's not needed for any of the code you posted nor my answer. `print()` is also a function call now, which has more overhead than the `print` statement, and Python 3 also adds an encoding step (albeit in C code) from unicode to bytes. – Martijn Pieters Mar 21 '14 at 11:12
  • 1
    No, I created the list beforehand in both versions. I can post code of the benchmark, if you find this interesting. In understand the overhead, but we're talking about almost an order of magnitude. – nickie Mar 21 '14 at 11:14
  • 2
    @nickie in my benchmark: `lst = range(100*1000) ; for i in lst: print i, ` took ~0.04s, while in python3 `lst = range(100*1000) ; print(*lst)` took ~0.08s – m.wasowski Mar 21 '14 at 11:20
  • @m.wasowski: I think the OP was using a loop in Python 3 as well. – Martijn Pieters Mar 21 '14 at 11:21
  • for loop in Python 3 doubles time (to ~0.15s) on my box – m.wasowski Mar 21 '14 at 11:28
  • @m.wasowski: `range` in Python 2 returns a list whereas in Python 3 a generator object. Anyway, the question was not primarily about performance and I feel reluctant to clutter it with benchmarking code. If you and/or Martijn think that continuing this discussion is interesting, I can post a new question. Thank you both, again. – nickie Mar 21 '14 at 11:30
  • I can reproduce a large increase in time in Python 3 for the `for i in L: print(i, end=' ')` loop, yes; about 4.5 times as much time over 10 repeats with `timeit` and `stdout` set to `/dev/null`. The difference lies in the function call (stack push and pop) and the more complex I/O structure (encoding unicode to bytes). – Martijn Pieters Mar 21 '14 at 11:38
  • To a terminal the performance should be a non-issue, but if the target is a file, someone might be tempted to do something like `print(*L, sep='\n', file=f)` for a very large list. The issue here -- possibly (the list would have to be *huge*) -- is that the interpreter will create 2 tuples from list `L` that exist for the duration of the call. – Eryk Sun Mar 21 '14 at 12:54
  • We can also use join as in My answer. – Deepak Yadav Jun 24 '18 at 15:01
  • @DeepakYadav: sure, but at the cost of creating a single larger string you then discard again, plus string objects for each and every value in the input list that isn't a string already. `print(..)` doesn't have to do most of that work, it just sends the data to the `stdout` buffer, which then can do any processing at the C level, and never has to create a new Python object in that process. That makes it all the more efficient. – Martijn Pieters Jun 24 '18 at 15:37
  • Note that joining a generator expression should be faster than joining a list; that is `' '.join(str(v) for v in range(100*1000))` is faster than `' '.join([str(v) for v in range(100*1000)])` – Bex Mar 11 '20 at 05:35
  • @Bex It is **not** faster because string joining needs to know the total length up front and so makes two passes. To be able to do that a generator expression is consumed into a list first and so is **slower**. If you actually timed your two expressions you’ll find that your assertion doesn’t hold. – Martijn Pieters Mar 11 '20 at 07:36
  • @Ben: see [Raymond Hettinger’s answer](https://stackoverflow.com/a/9061024) for timing runs. – Martijn Pieters Mar 11 '20 at 07:40
  • 3
    what is * called in this reference? and what is this printing suing * operator called? Could someone point me out to the documentation? Thank you – Nithin Gowda Oct 23 '20 at 16:39
  • 2
    @NithinGowda: That's part of the [call expression syntax](https://docs.python.org/3/reference/expressions.html#calls), and I call it *argument expansion*. It's not an operator. – Martijn Pieters Oct 24 '20 at 13:43
9

Although the accepted answer is absolutely clear, I just wanted to check efficiency in terms of time.

The best way is to print joined string of numbers converted to strings.

print(" ".join(list(map(str,l))))

Note that I used map instead of loop. I wrote a little code of all 4 different ways to compare time:

import time as t

a, b = 10, 210000
l = list(range(a, b))
tic = t.time()
for i in l:
    print(i, end=" ")

print()
tac = t.time()
t1 = (tac - tic) * 1000
print(*l)
toe = t.time()
t2 = (toe - tac) * 1000
print(" ".join([str(i) for i in l]))
joe = t.time()
t3 = (joe - toe) * 1000
print(" ".join(list(map(str, l))))
toy = t.time()
t4 = (toy - joe) * 1000
print("Time",t1,t2,t3,t4)

Result:

Time 74344.76 71790.83 196.99 153.99

The output was quite surprising to me. Huge difference of time in cases of 'loop method' and 'joined-string method'.

Conclusion: Do not use loops for printing list if size is too large( in order of 10**5 or more).

Community
  • 1
  • 1
Amit Dwivedi
  • 91
  • 1
  • 3
1
list = [1, 2, 3, 4, 5]
for i in list[0:-1]:
    print(i, end=', ')
print(list[-1])

do for loops really take that much longer to run?

was trying to make something that printed all str values in a list separated by commas, inserting "and" before the last entry and came up with this:

spam = ['apples', 'bananas', 'tofu', 'cats']
for i in spam[0:-1]:
    print(i, end=', ')
print('and ' + spam[-1])
mashkitty
  • 11
  • 2
1

Joining elements in a list space separated:

word = ["test", "crust", "must", "fest"]
word.reverse()
joined_string = ""
for w in word:
   joined_string = w + joined_string + " "
print(joined_string.rstrim())
TrickOrTreat
  • 821
  • 1
  • 9
  • 23