Skip to content

Pathlib Module Complexity

The pathlib module provides an object-oriented approach to filesystem path handling.

Classes and Methods

Method Time Space Notes
Path(str) O(n) O(n) Create Path from string
Path.cwd() O(1) O(n) Get current directory
Path.home() O(1) O(n) Get home directory
Path.exists() O(1) O(1) Check if path exists
Path.is_file() O(1) O(1) Check if path is file
Path.is_dir() O(1) O(1) Check if path is directory
Path.is_symlink() O(1) O(1) Check if path is symlink
Path.stat() O(1) O(1) Get file stats
Path.resolve() O(n) O(n) Resolve to absolute path
Path.iterdir() O(d) O(d) Iterate directory contents
Path.glob(pattern) O(n) O(1) per item n = directory entries checked, returns iterator
Path.rglob(pattern) O(n) O(1) per item n = total tree entries, returns iterator
Path.mkdir() O(1) O(1) Create directory
Path.rename(target) O(1) O(1) Rename path
Path.unlink() O(1) O(1) Delete file
Path.rmdir() O(1) O(1) Delete empty directory
Path.read_text() O(n) O(n) Read file as text
Path.read_bytes() O(n) O(n) Read file as bytes
Path.write_text() O(n) O(n) Write text to file
Path.write_bytes() O(n) O(n) Write bytes to file

Path Construction

Time Complexity: O(n)

Where n = length of the path string.

from pathlib import Path

# Simple path: O(n) where n = path length
path = Path('/home/user/documents/file.txt')  # O(27)

# Relative path: O(n)
path = Path('docs/README.md')  # O(13)

# Current directory: O(1) - system call
cwd = Path.cwd()

# Home directory: O(1) - system call
home = Path.home()

Space Complexity: O(n)

from pathlib import Path

# Stores the path string
path = Path('/' + 'a' * 10000)  # O(n) space

Path Operations

exists(), is_file(), is_dir()

Time Complexity: O(1)

from pathlib import Path

path = Path('file.txt')

# Single stat system call: O(1)
if path.exists():      # O(1) - stat call
    print('exists')

if path.is_file():     # O(1) - stat call
    print('is file')

if path.is_dir():      # O(1) - stat call
    print('is directory')

Space Complexity: O(1)

from pathlib import Path

path = Path('large_name' * 100)

# No additional memory needed
exists = path.exists()  # O(1) space

Path Resolution

resolve()

Time Complexity: O(n)

Where n = number of symlinks to follow and path components.

from pathlib import Path

# Simple resolution: O(n) where n = components
path = Path('docs/../files/./file.txt')
absolute = path.resolve()  # O(n) - normalize and resolve

# With symlinks: O(n) where n = symlinks + components
# Each symlink read is a system call
path = Path('/path/with/symlinks/file.txt')
absolute = path.resolve()  # O(n)

Space Complexity: O(n)

from pathlib import Path

# Stores resolved path
path = Path('relative/path').resolve()  # O(n) space

Directory Operations

iterdir()

Time Complexity: O(d)

Where d = number of directory entries.

from pathlib import Path

path = Path('/home/user')

# List all entries: O(d) where d = entries
for item in path.iterdir():  # O(d)
    print(item)

# Count entries: O(d)
count = sum(1 for _ in path.iterdir())  # O(d)

Space Complexity: O(d)

from pathlib import Path

path = Path('/home/user')

# Creates list of all entries
entries = list(path.iterdir())  # O(d) space

# Iterator uses O(1) space per entry
for item in path.iterdir():  # O(1) per iteration
    process(item)

glob()

Time Complexity: O(d)

Where d = number of entries to check against pattern.

from pathlib import Path

path = Path('.')

# Simple glob: O(d) where d = matching entries
py_files = list(path.glob('*.py'))  # O(d)

# Nested glob: O(d) for all matching
txt_files = list(path.glob('**/*.txt'))  # O(d)

# With pattern matching: O(d) where d = checked entries
results = list(path.glob('[a-z]*/data/*.json'))  # O(d)

Space Complexity: O(d)

from pathlib import Path

# Results stored in memory
matches = list(Path('.').glob('*'))  # O(d) space

# Iterator approach: O(1) space
for match in Path('.').glob('*'):  # O(1) per iteration
    process(match)

rglob()

Time Complexity: O(d)

Where d = total entries in directory tree.

from pathlib import Path

path = Path('src')

# Recursive glob: O(d) where d = all entries
all_py = list(path.rglob('*.py'))  # O(d)

# Equivalent to glob('**/*pattern')
all_txt = list(path.rglob('*.txt'))  # O(d)

Space Complexity: O(d)

from pathlib import Path

# All results in memory
matches = list(Path('.').rglob('*.py'))  # O(d) space

File I/O

read_text() / read_bytes()

Time Complexity: O(n)

Where n = file size.

from pathlib import Path

path = Path('data.txt')

# Read entire file: O(n) where n = file size
content = path.read_text()  # O(n)

# Read binary: O(n)
data = path.read_bytes()  # O(n)

# Read with encoding: O(n)
content = path.read_text(encoding='utf-8')  # O(n)

Space Complexity: O(n)

from pathlib import Path

# Stores entire file content
content = Path('large_file.txt').read_text()  # O(n) space

write_text() / write_bytes()

Time Complexity: O(n)

Where n = content size.

from pathlib import Path

path = Path('output.txt')

# Write text: O(n) where n = content size
path.write_text('Hello, World!')  # O(14)

# Write bytes: O(n)
path.write_bytes(b'Binary data')  # O(11)

# Overwrites file: O(n) regardless of original size
path.write_text('x' * 1000000)  # O(n)

Space Complexity: O(1)

from pathlib import Path

# Streaming write - no buffer needed
content = 'x' * 1000000
Path('file.txt').write_text(content)  # O(1) extra space

File System Modifications

Time Complexity: O(1)

from pathlib import Path

# Create directory: O(1) - single system call
Path('new_dir').mkdir()  # O(1)

# Create with parents: O(d) where d = depth
Path('a/b/c/d').mkdir(parents=True, exist_ok=True)  # O(d)

# Remove file: O(1)
Path('file.txt').unlink()  # O(1)

# Remove directory: O(1) - must be empty
Path('empty_dir').rmdir()  # O(1)

# Rename: O(1) - same filesystem
Path('old.txt').rename('new.txt')  # O(1)

Space Complexity: O(1)

from pathlib import Path

# No significant memory allocation
Path('dir').mkdir()  # O(1) space
Path('file.txt').unlink()  # O(1) space

Common Patterns

Safe File Operations

from pathlib import Path

# Check before operating
path = Path('file.txt')

if path.exists() and path.is_file():  # O(1) + O(1)
    content = path.read_text()  # O(n)

Directory Tree Processing

from pathlib import Path

# Process all files: O(d) + O(n_i) for each file
for file in Path('src').rglob('*.py'):  # O(d) to find files
    content = file.read_text()  # O(n_i) per file
    process(content)  # Process file content

Path Construction

from pathlib import Path

# Build paths: O(1) per operation
base = Path('data')
file = base / 'subdir' / 'file.txt'  # O(1) per /

# Multiple files
for name in files:
    path = base / name  # O(1) per iteration

Safe Deletion

from pathlib import Path
import shutil

path = Path('directory')

# Delete directory and contents: O(d) where d = total items
if path.is_dir():  # O(1)
    shutil.rmtree(path)  # O(d)

# Or using pathlib
# Path.rmdir() only works on empty directories

Comparison with os.path

from pathlib import Path
import os

# pathlib (object-oriented)
p = Path('data') / 'file.txt'  # O(1)
exists = p.exists()  # O(1)
content = p.read_text()  # O(n)

# os.path (functional)
path = os.path.join('data', 'file.txt')  # O(n)
exists = os.path.exists(path)  # O(1)
with open(path) as f:  # O(1)
    content = f.read()  # O(n)

# Both have same algorithmic complexity
# pathlib is more convenient and cleaner

Performance Characteristics

Best Practices

from pathlib import Path

# Good: Cache path objects
base = Path('/large/directory')
files = list(base.glob('*.py'))  # O(d) once

for file in files:  # Iterate cached results
    process(file)  # O(1) per file

# Bad: Repeated glob calls
for i in range(100):
    files = list(Path('.').glob('*.py'))  # O(d) * 100

Avoiding Deep Recursion

from pathlib import Path

# Good: Use glob for pattern matching
py_files = list(Path('src').rglob('*.py'))  # O(d) to find

# Avoid manual recursion if glob works
# Manual recursion has similar complexity but more overhead

Version Notes

  • Python 3.4+: pathlib introduced
  • Python 3.6+: improved performance
  • Python 3.10+: New methods and improvements
  • Python 3.13+: Additional optimization