Python - Read File into List

The most straightforward approach uses `readlines()`, which returns a list where each element represents a line from the file, including newline characters:

Key Insights

  • Python offers multiple methods to read files into lists, each optimized for different scenarios: readlines() for preserving line breaks, read().splitlines() for clean lines, and list comprehensions for filtering during read operations.
  • Memory efficiency matters when handling large files—use generator expressions with iter() or process line-by-line instead of loading entire files into memory at once.
  • Context managers with with statements automatically handle file closing and exception scenarios, eliminating resource leaks that plague manual file operations.

Basic File Reading Methods

The most straightforward approach uses readlines(), which returns a list where each element represents a line from the file, including newline characters:

with open('data.txt', 'r') as file:
    lines = file.readlines()

print(lines)
# Output: ['First line\n', 'Second line\n', 'Third line\n']

To remove trailing newline characters, combine readlines() with a list comprehension:

with open('data.txt', 'r') as file:
    lines = [line.rstrip('\n') for line in file.readlines()]

print(lines)
# Output: ['First line', 'Second line', 'Third line']

Alternatively, use read().splitlines() for cleaner output without manual stripping:

with open('data.txt', 'r') as file:
    lines = file.read().splitlines()

print(lines)
# Output: ['First line', 'Second line', 'Third line']

The splitlines() method handles various line terminators (\n, \r\n, \r) automatically, making it more robust across different operating systems.

Direct List Conversion

Convert a file object directly to a list using the list() constructor. File objects are iterators, so this approach reads line-by-line:

with open('data.txt', 'r') as file:
    lines = list(file)

print(lines)
# Output: ['First line\n', 'Second line\n', 'Third line\n']

Strip whitespace during conversion:

with open('data.txt', 'r') as file:
    lines = [line.strip() for line in file]

This method is memory-efficient because it iterates through the file rather than loading everything into memory first with read().

Filtering While Reading

Apply filters during the read operation to build targeted lists. This approach is more efficient than reading everything and filtering afterward:

# Read only non-empty lines
with open('data.txt', 'r') as file:
    lines = [line.strip() for line in file if line.strip()]

# Read lines matching a pattern
with open('logs.txt', 'r') as file:
    error_lines = [line.strip() for line in file if 'ERROR' in line]

# Read lines starting with specific character
with open('config.txt', 'r') as file:
    settings = [line.strip() for line in file if not line.startswith('#')]

Combine multiple conditions for complex filtering:

with open('data.csv', 'r') as file:
    valid_rows = [
        line.strip() 
        for line in file 
        if line.strip() and not line.startswith('#') and ',' in line
    ]

Handling Large Files

For files that exceed available memory, avoid loading the entire content at once. Use generators or process line-by-line:

def read_large_file(filepath, chunk_size=1000):
    """Read file in chunks, yielding lists of lines."""
    with open(filepath, 'r') as file:
        chunk = []
        for line in file:
            chunk.append(line.strip())
            if len(chunk) >= chunk_size:
                yield chunk
                chunk = []
        if chunk:  # Yield remaining lines
            yield chunk

# Process in chunks
for chunk in read_large_file('large_data.txt'):
    process_chunk(chunk)  # Your processing logic

For specific line ranges, use itertools.islice():

from itertools import islice

# Read lines 100-200
with open('data.txt', 'r') as file:
    lines = list(islice(file, 100, 200))

# Read first 50 lines
with open('data.txt', 'r') as file:
    lines = list(islice(file, 50))

Reading Structured Data

Parse CSV files into lists of lists:

import csv

with open('data.csv', 'r') as file:
    reader = csv.reader(file)
    rows = list(reader)

print(rows)
# Output: [['Name', 'Age', 'City'], ['Alice', '30', 'NYC'], ['Bob', '25', 'LA']]

For CSV with headers, separate header and data:

import csv

with open('data.csv', 'r') as file:
    reader = csv.reader(file)
    header = next(reader)
    data = list(reader)

print(f"Header: {header}")
print(f"Data rows: {len(data)}")

Read JSON arrays into Python lists:

import json

with open('data.json', 'r') as file:
    data = json.load(file)

# Assuming JSON contains an array
print(type(data))  # <class 'list'>

Character Encoding and Error Handling

Specify encoding explicitly to avoid issues with non-ASCII characters:

with open('data.txt', 'r', encoding='utf-8') as file:
    lines = file.readlines()

Handle encoding errors gracefully:

# Ignore errors
with open('data.txt', 'r', encoding='utf-8', errors='ignore') as file:
    lines = file.readlines()

# Replace problematic characters
with open('data.txt', 'r', encoding='utf-8', errors='replace') as file:
    lines = file.readlines()

Implement comprehensive error handling:

def safe_read_file(filepath):
    """Read file with error handling."""
    try:
        with open(filepath, 'r', encoding='utf-8') as file:
            return file.read().splitlines()
    except FileNotFoundError:
        print(f"File not found: {filepath}")
        return []
    except PermissionError:
        print(f"Permission denied: {filepath}")
        return []
    except UnicodeDecodeError:
        print(f"Encoding error in: {filepath}")
        # Retry with different encoding
        with open(filepath, 'r', encoding='latin-1') as file:
            return file.read().splitlines()

lines = safe_read_file('data.txt')

Performance Comparison

Different methods have varying performance characteristics. For a 10MB file with 100,000 lines:

import time

def benchmark_method(method_func, filepath):
    start = time.time()
    result = method_func(filepath)
    elapsed = time.time() - start
    return elapsed, len(result)

# Method 1: readlines()
def method1(filepath):
    with open(filepath, 'r') as f:
        return f.readlines()

# Method 2: read().splitlines()
def method2(filepath):
    with open(filepath, 'r') as f:
        return f.read().splitlines()

# Method 3: list comprehension
def method3(filepath):
    with open(filepath, 'r') as f:
        return [line.strip() for line in f]

# Run benchmarks
for method in [method1, method2, method3]:
    elapsed, count = benchmark_method(method, 'large_file.txt')
    print(f"{method.__name__}: {elapsed:.4f}s, {count} lines")

Generally, read().splitlines() performs fastest for small-to-medium files, while list comprehensions with direct iteration (for line in f) provide better memory efficiency for large files.

Practical Use Cases

Reading configuration files:

def load_config(filepath):
    """Load key-value configuration file."""
    config = {}
    with open(filepath, 'r') as file:
        for line in file:
            line = line.strip()
            if line and not line.startswith('#'):
                key, value = line.split('=', 1)
                config[key.strip()] = value.strip()
    return config

settings = load_config('app.conf')

Processing log files with filtering:

def extract_errors(log_file):
    """Extract error messages from log file."""
    with open(log_file, 'r') as file:
        return [
            line.strip() 
            for line in file 
            if 'ERROR' in line or 'CRITICAL' in line
        ]

errors = extract_errors('application.log')

Choose the method that matches your specific requirements: use readlines() for simple cases, list comprehensions for filtering, generators for large files, and specialized libraries like csv for structured data.

Liked this? There's more.

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