Backend / Python core / Tricky questions / 15_implicit_string_concat.md

Implicit string concatenation

Updated 3 interview angles 2 min read source
On this page5
  1. The gotcha
  2. Minimal repro
  3. Why it happens
  4. How to avoid
  5. Interview angle

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

python
# 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))   # 3

The 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:

python
"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. ruff flags this as ISC001 (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.