Implicit string concatenation
The gotcha
Adjacent string literals are concatenated at parse time. Useful for splitting long strings — devastating when a missing comma in a list silently merges two items.
Minimal repro
# Useful:
msg = ("This is a long message "
"that spans multiple lines "
"without explicit + .")
# Bug:
animals = [
"cat",
"dog"
"rabbit", # missing comma after "dog"
"fish",
]
print(animals) # ['cat', 'dograbbit', 'fish'] ← 3 items, not 4
print(len(animals)) # 3The compiler treats "dog" "rabbit" as "dograbbit" because they’re adjacent string literals. No warning. No error. Just silent bug.
Why it happens
PEP 3101 / language spec: any sequence of string/byte literals separated only by whitespace is concatenated at compile time, like C. This applies to literal strings only — not f-strings combined with regular strings:
"abc" "def" # "abcdef"
"abc" f"de{f}" # works in 3.12+, syntax error pre-3.12
"abc" + variable # runtime concat (different mechanism)It does not apply to expressions: s = "a"; "abc" s is a SyntaxError, not concatenation.
How to avoid
- Use a linter (
ruff,pylint) with the rule enabled.ruffflags this asISC001(implicit string concat). - Add trailing commas in multi-line lists and tuples — most modern formatters (
black,ruff format) enforce this. - For multi-line strings, prefer triple-quoted or explicit
+if clarity helps. - Inspect lists if their length is wrong by exactly one — common cause is a swallowed comma.
Interview angle 3
- “Find the bug in this list.” - a missing comma between two string literals, so Python concatenates them at compile time and the list is one element shorter than it looks. Nothing errors, and the resulting string is a plausible-looking value.
- “Why does Python do this at all?” - so a long literal can be split across
lines inside parentheses without a
+at every break. It is a genuinely useful feature that happens to make one specific typo silent. - “How do you stop it reaching production?” - a linter rule, since this is
exactly what static analysis is good at -
ruff’s implicit-concat check flags it. A trailing comma on every element also makes the missing one visible in a diff.