tripleMalt
tripleMalt

Reputation: 263

Is concatenating with "+" more efficient than separating with "," when using print?

I just noticed that if I use + for concatenation in the print() function and run the code in the shell the text appears more quickly. Whereas, when using ,, the text appears much slower as if with a "being typed" animation effect.

Is there a efficiency difference between these two?

Upvotes: 20

Views: 6376

Answers (7)

Dimitris Fasarakis Hilliard
Dimitris Fasarakis Hilliard

Reputation: 160607

Though I wouldn't suspect a large discrepancy between these, they are obviously slightly different.

A print call that concatenates literal strings might be joined by CPython's peephole optimizer before being printed thereby resulting in faster execution, this is probably what you're seeing. Besides that, with small strings, the fact that only one argument is passed and, as a result, sep isn't used is also a small benefit.

With larger strings, the need to create a large temporary string to hold their concatenation negates all speed differences achieved. (The fact that sep isn't used and only one argument is passed is trumped due to the size and their concatenation)

Using , in a print call will pass each string as an argument and separate it using the default sep. While this obviously requires a bit more work, it is constant work that, again, disappears when large strings are involved.

So, with small strings that actually get caught by the optimizer, concatenation is a bit faster:

%timeit print("a" + "b", file=f)
1000000 loops, best of 3: 1.76 µs per loop

%timeit print("a", "b", sep='', file=f)
100000 loops, best of 3: 2.48 µs per loop

Even when the optimizer can't join them:

a = "a"; b = "b"

%timeit print(a + b, file=f)
1000000 loops, best of 3: 2 µs per loop

%timeit print(a, b, sep='', file=f)
100000 loops, best of 3: 2.45 µs per loop

when the string sizes increase, this small difference is eclipsed:

s1, s2 = "s" * 100000, "s"*100000
%timeit print(s1 + s2, file=f)
1000 loops, best of 3: 374 µs per loop
%timeit print(s1, s2, sep='', file=f)
1000 loops, best of 3: 373 µs per loop

Upvotes: 26

user2124834
user2124834

Reputation:

edit: Seems the question was not so much about the nature of the operations as their speed, which is not discussed in this answer!

The difference is that with + you use concatenation to create a larger string to pass to the print function, while with , you pass multiple strings to the print function. Note that these behaviours are not special for the print function: concatenation is just a method on strings, and comma is always used to separate function arguments.

For example, using concatenation:

print('hello' + ' ' + 'world')

This first concatenates the three strings to form 'hello world', and then prints that.

While using multiple arguments:

print('hello', 'world')

This passes two strings to the print function. As you can read here, the print function takes one or multiple objects as arguments, and prints them separated by another argument, sep, which by default is a space. So this produces the same output as the previous example.

Note that any number of arguments can be passed to the print function, and that these arguments in themselves can be concatenated strings:

print('i' + ' ' + 'want', 'to', 'print', 'some', 'strings')

The nice part is that you can specify the sep argument to change the behaviour:

print('mary', 'peter', 'bob', sep=' and ')

Result: mary and peter and bob

Upvotes: 20

Błotosmętek
Błotosmętek

Reputation: 12927

The obvious difference is that print(a, b) will put a separator (by default - a single space) between values of a and b, while print(a + b) won't. Performance-wise I would expect the comma version to be faster, as the plus version requires building a new string.

Update: using following code:

import timeit

t1 = timeit.timeit('print("aa", "bb")')
t2 = timeit.timeit('print("aa" + " " + "bb")')

print(t1, t2)

I've got 9.997510432032868 11.018277243943885 ie. about 10% difference in favour of the comma; however using slightly longer strings:

t1 = timeit.timeit('print("aaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbb")')
t2 = timeit.timeit('print("aaaaaaaaaaaaaaa"+" "+"bbbbbbbbbbbbbbbb")')

tipped the balance: 18.56978454696946 18.07760854391381. Then I redirected output to a file and obtained even more interesting results: 0.730336288921535 0.39260527514852583 for shorter and 0.7751083469484001 0.5140565759502351 for longer strings. Apparently, the results are more heavily influenced by scrolling speed of my terminal than by Python code.

Upvotes: 3

Hadi Farhadi
Hadi Farhadi

Reputation: 1761

print(a + b + c), evaluates an expression and passes a single argument to print. The second, print(a, b, c), just passes three arguments to print. This is almost the same output purely by chance: that's how print works. The second is not doing any concatenation, and is simply outputting each value separated by a space (which is print's default behavior).

the plus in the expression is doing concatenation, but the comma is not doing concatenation.

Concatenation creates each string in memory, and then combines them together at their ends in a new string (so this may not be very memory friendly), and then prints them to your output at the same time

Upvotes: 3

Ma0
Ma0

Reputation: 15204

You can also take a look at the bytecode for both using dis.

import dis

def f1():
    print('Hello ' + 'world!')


def f2():
    print('Hello', 'world!')


print(dis.dis(f1))

 62           0 LOAD_GLOBAL              0 (print)
              3 LOAD_CONST               3 ('Hello world!')
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 POP_TOP
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE
None


print(dis.dis(f2))
 66           0 LOAD_GLOBAL              0 (print)
              3 LOAD_CONST               1 ('Hello')
              6 LOAD_CONST               2 ('world!')
              9 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
             12 POP_TOP
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
None

You can see that the print with the comma calls LOAD_CONST twice in this case (or as many times as there are variables\strings). This is an indication that concatenation is faster and will get progressively faster the more strings you concatenate vs comma-separate.

Upvotes: 1

developer_hatch
developer_hatch

Reputation: 16214

If you use + operator, at the end of the creation of the whole string, and only after that, it will be printed, with the , it would be created by parts and printed as well. And as a lot of users already said, there is another factor, the concat of " " (white space), it takes times too.

Upvotes: 2

binu.py
binu.py

Reputation: 1226

+ can be used with strings to concatenate 2 strings. However in python 2.X , is used in print to print item inline but in python 3.X if you put a , between 2 items the compiler converts the two items to a tuple. When used inside a print + is used to concatenate and hence they are printed together. but using , prints them with a space as it is printing 2 items of a tuple. eg,

In [1]: print('abcd'+'pqrs')
abcdpqrs

In [2]: print('abcd','pqrs')
abcd pqrs

In [3]: x=('abcd'+'pqrs')

In [4]: y=('abcd','pqrs')

In [5]: x
Out[5]: 'abcdpqrs'

In [6]: y
Out[6]: ('abcd', 'pqrs')

In [7]: type(y)
Out[7]: tuple

In [8]: type(x)
Out[8]: str

Upvotes: 2

Related Questions