sent2 + word + word + word + word + word creates multiple temporary str objects, roughly equivalent to
t1 = sent2 + word
t2 = t1 + word
t3 = t2 + word
t4 = t3 + word
sent_2= t4 + word
Creating all these objects (and copying the ever-growing values of one temporary value into another) results in a quadratic runtime.
''.join([word] * num), on the other hand, gets all the strings to concatenate at once in a single list, so it can allocate one result string and copy the substring in place in linear time.
The first example,
for _ in range(num):
sent += word
should be equivalent to repeated concatenation. But, CPython in particular optimizes this by recognizing that nobody can access the value of sent while sent + word is being computed, so it "cheats" and updates sent in place, with no new string being allocated to assign back to sent. This means you still have a linear-time operation, like ''.join, but with extra overhead due to iterating over the string in Python rather than at the C level of the interpreter.
num, to assess the big-O complexity of each approach?+symbol) in Python is very slow. Using.join()is much faster. It's that simple.strvalues are immutable. But, CPython has an optimization that detects thatsent + wordis being assigned back tosent, and so updatessentin-place anyway.+=for strings. This is a common question, but I'm struggling to find a proper canonical. But see e.g. stackoverflow.com/questions/2791931.