Sign in to your Python Morsels account to save your screencast settings.
Don't have an account yet? Sign up here.
Let's talk about implicit string concatenation in Python.
Take a look at this line of Python code:
>>> print("Hello" "world!")
It looks kind of like we're passing multiple arguments to the built-in print
function.
But we're not:
>>> print("Hello" "world!")
Helloworld!
If we pass multiple arguments to print
, Python will put spaces between those values when printing:
>>> print("Hello", "world!")
Hello world!
But Python wasn't doing.
Our code from before didn't have commas to separate the arguments (note the missing comma between "Hello"
and "world!"
):
>>> print("Hello" "world!")
Helloworld!
How is that possible?
This seems like it should have resulted in a SyntaxError
!
A string literal is the syntax that we use in Python to create brand new strings:
>>> "This is a string"
'This is a string'
>>> 'This is also a string'
'This is also a string'
>>> """Here's another string"""
"Here's another string"
String literals involve using some variation of quote characters to create a string.
If we write multiple string literals next to each other, Python will concatenate those strings:
>>> message = "Hello" "world"
>>> message
'Helloworld'
It's as if we put a plus sign (+
) between them.
But we didn't:
>>> message = "Hello" "world"
>>> message
'Helloworld'
>>> message = "Hello" + "world"
>>> message
'Helloworld'
This is called implicit string concatenation.
It's a bit of an odd feature, but it can be handy sometimes.
Take a look at this very long string:
long_string = "This is a very long string that goes on and on and might even wrap to the next line in your editor, which may make it challenging to read."
We could break this string up into smaller strings over multiple lines, and then concatenate the substrings together:
long_string = (
"This is a very long string that goes on and on " +
"and might even wrap to the next line in your editor, " +
"which may make it challenging to read."
)
We're using the plus operator to concatenate these strings.
But since they're all string literals, we could instead rely on implicit string concatenation:
long_string = (
"This is a very long string that goes on and on "
"and might even wrap to the next line in your editor, "
"which may make it challenging to read."
)
This is the situation where you're most likely to see implicit string concatenation used: to break up a long string literal into smaller strings over multiple lines, putting parentheses around them to create an implicit line continuation. And relying on the lack of an operator between those literals to make implicit string concatenation happen.
Even in a situation like this one, I usually prefer to avoid implicit string concatenation, as I find that it often causes more confusion than it's worth.
Also, there's usually a better alternative.
For example, here's some code that uses implicit string concatenation to concatenate many strings that represent lines of text into a single string:
def copyright():
print(
"Copyright (c) 1991-2000 ACME Corp\n"
"All Rights Reserved.\n\n"
"Copyright (c) 2000-2030 Cyberdyne\n"
"All Rights Reserved."
)
You might think that we could use a multiline string for this instead. And we could.
But we would need to remove the indentation from our string, which looks a bit odd:
def copyright():
print("""
Copyright (c) 1991-2000 ACME Corp
All Rights Reserved.
Copyright (c) 2000-2030 Cyberdyne
All Rights Reserved.""".strip("\n")
)
But Python has a dedent
function in the textwrap
module just for this situation:
from textwrap import dedent
def copyright():
print(dedent("""
Copyright (c) 1991-2000 ACME Corp
All Rights Reserved.
Copyright (c) 2000-2030 Cyberdyne
All Rights Reserved.
""").strip("\n"))
For representing multiple lines of text, I prefer to use multiline strings and the textwrap.dedent
function instead of using implicit string concatenation.
Another reason I tend to avoid implicit string concatenation is that it can sometimes cause bugs by accidentally using it.
Here's some code that makes a list of strings:
task_list = [
"Buy groceries",
"Do dishes",
"Do laundry",
"Practice Python"
]
This list has four strings in it:
>>> len(task_list)
4
Let's modify this list to move the last string to the beginning:
task_list = [
"Practice Python"
"Buy groceries",
"Do dishes",
"Do laundry",
]
When we do this, we'll see that this list no longer has the same length:
>>> len(task_list)
3
It now has only three items!
This happened because we're now accidentally using implicit string concatenation:
>>> task_list
['Practice PythonBuy groceries', 'Do dishes', 'Do laundry']
We don't have a comma after the first item in our list, so Python is concatenating that string literal with the one just after it:
task_list = [
"Practice Python"
"Buy groceries",
"Do dishes",
"Do laundry",
]
This is one of the reasons that I prefer to use trailing commas after the last item in a multiline list, or the last argument in a multiline function call:
task_list = [
"Buy groceries",
"Do dishes",
"Do laundry",
"Practice Python",
]
This can help avoid an accidental use of implicit string concatenation.
Code linters like Pylint, Flake8, and Ruff can often be configured to disallow the use of implicit string concatenation.
For example, for Flake8 you can install the flake8-no-implicit-concat plugin:
$ pip install flake8-no-implicit-concat
And for Ruff, you can enable implicit string concatenation checking and also disable multi-line implicit string concatenation:
[tool.ruff.lint]
select = ["ISC"]
[tool.ruff.lint.flake8-implicit-str-concat]
allow-multiline = false
So if you find this feature jarring enough that you'd like to never use it in your code, you can probably configure your linter to disallow it entirely.
The next time you see two string literals next to each other, keep in mind that Python will automatically concatenate them.
Some folks rely on this as a feature, but others consider it a bug waiting to happen.
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
Sign in to your Python Morsels account to track your progress.
Don't have an account yet? Sign up here.