Python - Multiline Strings

Triple-quoted strings use three consecutive single or double quotes and preserve all whitespace, including newlines and indentation. This is the most common approach for multiline text.

Key Insights

  • Python offers three distinct approaches for multiline strings: triple quotes for literals, parenthesized implicit concatenation for compile-time joining, and backslash continuation for breaking long lines without adding newlines.
  • Triple-quoted strings preserve whitespace and newlines exactly as written, making them ideal for SQL queries, JSON templates, and documentation, but requiring careful indentation management to avoid unwanted leading spaces.
  • String formatting with multiline strings using f-strings, format(), or template strings enables dynamic content generation while maintaining readability in configuration files, reports, and API payloads.

Triple-Quoted String Literals

Triple-quoted strings use three consecutive single or double quotes and preserve all whitespace, including newlines and indentation. This is the most common approach for multiline text.

# Basic triple-quoted string
message = """This is a multiline string.
It spans multiple lines.
All whitespace is preserved."""

print(message)
# Output:
# This is a multiline string.
# It spans multiple lines.
# All whitespace is preserved.

Triple quotes work with both single and double quotes, though double quotes are conventional:

sql_query = '''
    SELECT 
        user_id,
        username,
        email
    FROM users
    WHERE status = 'active'
    ORDER BY created_at DESC
'''

The primary challenge with triple-quoted strings is managing indentation. The string captures exactly what you write, including leading spaces:

def get_config():
    config = """
    {
        "database": "postgres",
        "host": "localhost"
    }
    """
    return config

print(repr(get_config()))
# Output: '\n    {\n        "database": "postgres",\n        "host": "localhost"\n    }\n    '

Use textwrap.dedent() to remove common leading whitespace:

from textwrap import dedent

def get_config():
    config = dedent("""
        {
            "database": "postgres",
            "host": "localhost"
        }
    """).strip()
    return config

print(get_config())
# Output: Clean JSON without leading spaces

Implicit String Concatenation

Python automatically concatenates adjacent string literals at compile time. This approach creates a single string without newlines, useful for long strings that need to fit within line length limits.

error_message = (
    "Unable to process request: "
    "the specified resource does not exist "
    "or you lack sufficient permissions "
    "to access it."
)

print(error_message)
# Output: Unable to process request: the specified resource does not exist or you lack sufficient permissions to access it.

This technique works well for SQL queries where you want control over whitespace:

query = (
    "SELECT u.id, u.name, COUNT(o.id) as order_count "
    "FROM users u "
    "LEFT JOIN orders o ON u.id = o.user_id "
    "WHERE u.created_at > '2024-01-01' "
    "GROUP BY u.id, u.name "
    "HAVING COUNT(o.id) > 5"
)

Parentheses are optional but improve readability. Without them, strings must be on consecutive lines:

# Works but less clear
path = "/api/v1/users" "/123" "/orders"

# Better with parentheses
path = (
    "/api/v1/users"
    "/123"
    "/orders"
)

Implicit concatenation only works with literals, not variables:

base = "Hello"
# This raises SyntaxError
# message = base " World"

# Use explicit concatenation for variables
message = base + " World"

Backslash Line Continuation

Backslashes allow breaking a single logical line across multiple physical lines without introducing newlines. This preserves the string as a single line.

long_string = "This is a very long string that \
would exceed the line length limit \
so we break it across multiple lines."

print(repr(long_string))
# Output: 'This is a very long string that would exceed the line length limit so we break it across multiple lines.'

Backslash continuation is less common than other methods but useful in specific scenarios:

file_path = "/very/long/path/to/some/deeply/nested/directory/structure/\
that/contains/important/files/data.json"

regex_pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.\
[a-zA-Z]{2,}$"

Be cautious with trailing whitespace after backslashes—it causes syntax errors:

# This will raise SyntaxError if there's a space after \
# message = "Hello \  
# World"

Multiline Strings with Formatting

F-strings work seamlessly with multiline strings, enabling dynamic content generation:

def generate_email(name, order_id, total):
    email = f"""
    Dear {name},
    
    Your order #{order_id} has been confirmed.
    Total amount: ${total:.2f}
    
    Thank you for your business!
    """
    return dedent(email).strip()

print(generate_email("Alice", 12345, 299.99))

For complex templates, combine multiline strings with the format() method:

report_template = """
Performance Report
==================
Server: {server_name}
Uptime: {uptime_hours:.1f} hours
Requests: {request_count:,}
Error Rate: {error_rate:.2%}
"""

report = report_template.format(
    server_name="web-01",
    uptime_hours=168.5,
    request_count=1500000,
    error_rate=0.0023
)

print(report)

For highly complex templates, use string.Template for safer substitution:

from string import Template

config_template = Template("""
[database]
host = $db_host
port = $db_port
name = $db_name

[cache]
host = $cache_host
ttl = $cache_ttl
""")

config = config_template.substitute(
    db_host="localhost",
    db_port=5432,
    db_name="production",
    cache_host="redis.local",
    cache_ttl=3600
)

Practical Applications

SQL Query Building

def build_user_query(filters):
    conditions = []
    params = {}
    
    if filters.get('status'):
        conditions.append("status = :status")
        params['status'] = filters['status']
    
    if filters.get('min_age'):
        conditions.append("age >= :min_age")
        params['min_age'] = filters['min_age']
    
    where_clause = " AND ".join(conditions) if conditions else "1=1"
    
    query = f"""
        SELECT 
            id,
            username,
            email,
            status,
            age
        FROM users
        WHERE {where_clause}
        ORDER BY created_at DESC
        LIMIT :limit
    """
    
    params['limit'] = filters.get('limit', 100)
    return dedent(query).strip(), params

query, params = build_user_query({'status': 'active', 'min_age': 18, 'limit': 50})

API Response Templates

def create_error_response(code, message, details=None):
    response = {
        "error": {
            "code": code,
            "message": message
        }
    }
    
    if details:
        response["error"]["details"] = details
    
    # Pretty-printed JSON
    import json
    return json.dumps(response, indent=2)

error_json = create_error_response(
    "VALIDATION_ERROR",
    "Invalid input parameters",
    ["Email format is invalid", "Password too short"]
)

Documentation Strings

class DataProcessor:
    """
    Process and transform data from various sources.
    
    This class provides methods for:
    - Loading data from CSV, JSON, and XML files
    - Validating data against predefined schemas
    - Transforming data using custom pipelines
    - Exporting results to multiple formats
    
    Example:
        processor = DataProcessor()
        data = processor.load_csv('input.csv')
        validated = processor.validate(data, schema)
        result = processor.transform(validated)
    """
    
    def transform(self, data):
        """
        Apply transformation pipeline to data.
        
        Args:
            data: Input data as list of dictionaries
            
        Returns:
            Transformed data with applied rules
            
        Raises:
            ValueError: If data format is invalid
        """
        pass

Choose the appropriate multiline string technique based on your needs: triple quotes for preserving formatting, implicit concatenation for controlled whitespace, and backslash continuation for single-line strings split across multiple lines. Combine these with formatting methods to build maintainable, readable code.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.