How to indent multiple lines in Python
Struggling with Python indentation? Learn to indent multiple lines with various methods, tips, real-world examples, and debugging help.

Proper indentation in Python is essential for code execution and readability. It defines the structure of your loops, functions, and classes and is a fundamental concept for every developer.
In this article, you'll learn several techniques to indent multiple lines efficiently. We'll cover practical tips, real-world applications, and advice to debug common indentation errors.
Basic indentation with spaces
text = """First line
Second line
Third line"""
indented_text = ""
for line in text.split("\n"):
indented_text += " " + line + "\n"
print(indented_text)--OUTPUT--First line
Second line
Third line
This approach manually adds indentation by processing each line of a string individually. The code first uses text.split("\n") to break the multi-line string into a list of separate lines. This gives you an iterable collection to work with, similar to how commenting in Python helps organize and structure your code.
The for loop then processes each line from that collection. Inside the loop, the expression " " + line concatenates four spaces to the front of the line, creating the indentation. This method is a foundational technique for programmatically controlling whitespace in your text output.
Standard indentation techniques
Moving past the basic loop, Python provides several powerful, built-in functions and syntax features to make indenting multiple lines much simpler.
Using the textwrap.indent() function
import textwrap
text = """First line
Second line
Third line"""
indented_text = textwrap.indent(text, prefix=" ")
print(indented_text)--OUTPUT--First line
Second line
Third line
The textwrap module offers a more direct way to handle text formatting. Its textwrap.indent() function is specifically designed for this task, applying a given prefix to every line in a string and saving you from writing a manual loop.
- The function takes the text as its first argument.
- The
prefixargument specifies the string to add, such as" "for standard indentation.
This approach is cleaner and memory-efficient than manually iterating through each line. It's the recommended method for simple, block-level indentation tasks.
Using string methods with splitlines() and join()
text = """First line
Second line
Third line"""
indented_text = "\n".join(" " + line for line in text.splitlines())
print(indented_text)--OUTPUT--First line
Second line
Third line
This approach combines two string methods into a compact one-liner. It’s a common Pythonic pattern that chains splitlines() and join() to manipulate text efficiently.
- First,
text.splitlines()breaks the string into a list, with each line as an item. - A generator expression then iterates through this list, prepending four spaces to each line.
- Finally,
"\n".join()stitches the newly indented lines back together into a single string, separated by newlines.
Using multi-line string formatting with triple quotes
indent = " " * 4
indented_text = f"""{indent}First line
{indent}Second line
{indent}Third line"""
print(indented_text)--OUTPUT--First line
Second line
Third line
This technique leverages Python's f-strings and triple quotes for direct, inline indentation. It's a highly readable approach when your text is static and you want to see the final structure right in your code. For more advanced techniques with multiline strings in Python, you can explore additional formatting options.
- First, you create a variable like
indent = " " * 4to hold your indentation string. - Then, within a triple-quoted f-string, you place
{indent}at the beginning of each line you want to indent.
This method is visually clean because the formatting is explicit and part of the string itself, making your code's intent immediately clear.
Advanced indentation approaches
For more control over your text formatting, you can move beyond standard functions and create specialized solutions for complex or repetitive indentation needs.
Creating a context manager for indentation
class Indenter:
def __init__(self, level=0):
self.level = level
def __enter__(self):
self.level += 1
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.level -= 1
def print(self, text):
print(" " * self.level + text)
with Indenter() as indent:
indent.print("First level")
with indent:
indent.print("Second level")--OUTPUT--First level
Second level
A context manager provides a robust way to handle resources that need setup and teardown—in this case, indentation levels. The Indenter class lets you use a with statement to automatically manage indentation for nested blocks of text. This approach is perfect for generating structured output like code or logs where hierarchy matters.
- The
__enter__method runs when you enter awithblock, increasing the indentation level. - When the block is exited, the
__exit__method runs, decreasing the level back down. - The custom
printmethod applies the current indentation before printing.
Using regex for selective indentation
import re
text = """def function():
# This is already indented
pass # This needs indentation"""
# Only indent lines that don't already have whitespace at the beginning
indented_text = re.sub(r"^(\S)", r" \1", text, flags=re.MULTILINE)
print(indented_text)--OUTPUT--def function():
# This is already indented
pass # This needs indentation
Regular expressions offer precise control for complex situations. This method uses re.sub to add indentation only where it's needed, leaving already indented lines untouched. It’s a powerful way to format text conditionally, especially when dealing with pre-formatted code snippets.
- The pattern
r"^(\S)"targets any line that starts with a non-whitespace character. - The
re.MULTILINEflag makes the^anchor match the beginning of each line. - The replacement string
r" \1"inserts four spaces and then reinserts the original character, indenting only the lines that match the pattern.
Creating a reusable indentation utility
def indent_block(text, indent_level=1, indent_char=" "):
prefix = indent_char * indent_level
if isinstance(text, list):
return [prefix + line for line in text]
else:
return "\n".join(prefix + line for line in text.splitlines())
code_block = "for i in range(3):\n print(i)"
print(indent_block(code_block, indent_level=2))--OUTPUT--for i in range(3):
print(i)
This approach packages the logic into a versatile function, indent_block, that you can reuse across your projects. It’s built for flexibility, handling both multi-line strings and lists of strings automatically. This saves you from writing repetitive formatting code for different scenarios.
- The function intelligently checks the input type with
isinstance(), applying the indentation correctly whether you provide a single block of text or pre-split lines. - You can customize the indentation with the
indent_levelandindent_chararguments, making it adaptable to any coding style or formatting need.
Move faster with Replit
Replit is an AI-powered development platform where all Python dependencies come pre-installed, so you can skip setup and start coding instantly. While mastering individual techniques is important, Agent 4 helps you move from piecing together functions to building complete applications.
Instead of manually formatting text, you can describe the app you want to build, and the Agent will take it from an idea to a working product:
- A documentation helper that takes raw code and automatically applies consistent indentation for embedding in tutorials.
- A log file beautifier that parses unstructured logs and indents nested events to make debugging easier.
- A configuration generator that creates structured YAML or JSON files from a simple list of settings, handling all the necessary nesting and spacing.
Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.
Common errors and challenges
Even with the right techniques, you might run into a few common indentation issues, but they're usually straightforward to fix.
Fixing the TabError: Mixing tabs and spaces
Python raises a TabError when you mix tabs and spaces for indentation within the same code block. Because different text editors interpret the width of a tab character differently, mixing them creates ambiguity that Python's interpreter can't resolve.
The best practice, recommended by the PEP 8 style guide, is to configure your code editor to use spaces exclusively. Most editors have a setting to automatically convert tabs to a set number of spaces, typically four, which prevents this error entirely.
Debugging IndentationError: Inconsistent indentation levels
An IndentationError is one of the most frequent errors for new Python developers. It occurs when a line of code has an incorrect level of indentation, either too much or not enough, breaking the logical structure.
You'll often see this with control structures. For example, an else statement might not be aligned with its corresponding if, or a line inside a loop might be indented differently from the others. The fix is to ensure every line in a block is indented consistently.
Handling unexpected indentation in multiline strings with dedent()
Sometimes the problem isn't in your code's logic but in your multiline strings. When you define a triple-quoted string inside an indented block, like a function, the string itself captures that leading whitespace.
To clean this up, you can use the textwrap.dedent() function. It intelligently removes the common leading whitespace from every line in the string. This is incredibly useful for preserving the relative indentation within your string while removing the indentation from the surrounding code.
Fixing the TabError: Mixing tabs and spaces
This error is a classic "gotcha" where invisible characters cause visible problems. It happens when you inadvertently mix tabs and spaces for indentation, which Python strictly forbids. The following function demonstrates how easily this can happen and what it looks like.
def calculate_sum(numbers):
total = 0 # This line uses a tab
for num in numbers: # This line uses spaces
total += num
return total
print(calculate_sum([1, 2, 3]))
The calculate_sum function fails because the total = 0 line is indented with a tab, while the following for loop uses spaces. This mix of invisible characters triggers the TabError. The corrected version below shows how to resolve this.
def calculate_sum(numbers):
total = 0
for num in numbers:
total += num
return total
print(calculate_sum([1, 2, 3]))
The corrected code resolves the error by using consistent spacing. By replacing the tab with four spaces, every line in the calculate_sum function is indented uniformly, satisfying Python's structural rules. This error often appears when you copy and paste code, as different editors can introduce a mix of tabs and spaces. The best defense is to configure your editor to always use spaces for indentation, which prevents the problem from happening in the first place.
Debugging IndentationError: Inconsistent indentation levels
An IndentationError occurs when lines in the same code block don't align. Python relies on consistent spacing to define its structure, so even a single misplaced space can break your script. The process_data function below demonstrates this common issue.
def process_data(data):
if data:
result = []
for item in data:
filtered = item.strip() # 3 spaces instead of 4
return result
return None
Inside the for loop, the filtered = item.strip() line has an unexpected amount of indentation. This misalignment breaks the logical block, causing the error. The corrected code shows how to fix this alignment.
def process_data(data):
if data:
result = []
for item in data:
filtered = item.strip() # Consistent 4 spaces
return result
return None
The fix is simple: the corrected code aligns filtered = item.strip() properly within the for loop. By using a consistent four spaces, every statement inside the block shares the same indentation level, which satisfies Python's structural rules. This error often appears when refactoring or copying code, so it's a good habit to double-check alignment inside loops and conditional statements to keep your script running smoothly.
Handling unexpected indentation in multiline strings with dedent()
When you define a multiline string inside an indented function, the string itself inherits that extra whitespace. This can mess up your output, especially with formats like HTML where spacing is significant. The get_html function below shows this problem in action.
def get_html():
html = """
<div>
<h1>Title</h1>
</div>
"""
return html.strip()
Here, the html.strip() method only cleans up the outer whitespace of the entire string block, leaving the unwanted indentation on each inner line. The corrected code below shows how to address this properly.
import textwrap
def get_html():
html = textwrap.dedent("""
<div>
<h1>Title</h1>
</div>
""")
return html.strip()
The corrected code uses textwrap.dedent() to remove the common leading whitespace from every line in the string. Unlike strip(), which only cleans the outer edges of the entire string block, dedent() preserves the string's internal structure while removing the unwanted indentation from the surrounding code.
This is crucial when you define formatted text like HTML or YAML inside an indented function, as it ensures your output isn't skewed by extra spaces.
Real-world applications
Mastering indentation isn't just about avoiding errors; it’s about building tools that generate clean, structured output in practical applications.
Creating a simple CLI tree view with indentation
You can build a simple command-line tree view by writing a recursive function that adjusts indentation based on the data's nesting level.
def display_tree(items, level=0):
for item in items:
print(" " * level + "├── " + item["name"])
if "children" in item and item["children"]:
display_tree(item["children"], level + 1)
file_tree = [
{
"name": "project",
"children": [
{"name": "main.py"},
{"name": "data", "children": [{"name": "config.json"}]}
]
}
]
display_tree(file_tree)
This code uses recursion in Python—a technique where a function calls itself—to print a nested data structure. The display_tree function processes a list of items, and the level parameter keeps track of the current depth to calculate the indentation.
- For each item, it prints the name, prefixed with spaces based on its
level. - If an item contains a
childrenkey, the function calls itself with the nested list and an incrementedlevel.
This process repeats until all nested items are printed, creating a visual tree from the data.
Creating a simple Python code formatter with indent_level
You can build a simple code formatter by creating a function that manages an indent_level to apply correct spacing based on syntax cues.
def format_simple_code(code):
lines = code.split('\n')
formatted_lines = []
indent_level = 0
for line in lines:
stripped = line.strip()
if not stripped: # Skip empty lines
continue
formatted_lines.append(' ' * indent_level + stripped)
if stripped.endswith(':'):
indent_level += 1
return '\n'.join(formatted_lines)
code = """def greet(name):
message = f"Hello, {name}!"
print(message)"""
print(format_simple_code(code))
This format_simple_code function rebuilds your code with proper spacing. It iterates through each line, using an indent_level variable to track the current depth.
- Before adding a line, it prepends the correct number of spaces based on the current
indent_level. - After adding the line, it checks if the line ends with a colon (
:). If it does, it increments theindent_levelfor all subsequent lines.
This simple heuristic allows the function to automatically format blocks that follow statements like def or for, creating structured output from unformatted code using techniques similar to vibe coding.
Get started with Replit
Turn your knowledge into a real tool with Replit Agent. Try "a Python script that auto-formats code snippets" or "a utility that converts JSON to an indented tree view".
The Agent writes the code, tests for errors, and deploys your app. Start building with Replit.
Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.
Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.



