Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Part of a 72-plugin marketplace with 112 AI agents and 146 skills for Claude Code development automation.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
SKILL.md
1---2name: python-performance-optimization3description: Profile and optimize Python code using cProfile, memory profilers, and performance best practices. Use when debugging slow Python code, optimizing bottlenecks, or improving application performance.4---56# Python Performance Optimization78Comprehensive guide to profiling, analyzing, and optimizing Python code for better performance, including CPU profiling, memory optimization, and implementation best practices.910## When to Use This Skill1112- Identifying performance bottlenecks in Python applications13- Reducing application latency and response times14- Optimizing CPU-intensive operations15- Reducing memory consumption and memory leaks16- Improving database query performance17- Optimizing I/O operations18- Speeding up data processing pipelines19- Implementing high-performance algorithms20- Profiling production applications2122## Core Concepts2324### 1. Profiling Types2526- **CPU Profiling**: Identify time-consuming functions27- **Memory Profiling**: Track memory allocation and leaks28- **Line Profiling**: Profile at line-by-line granularity29- **Call Graph**: Visualize function call relationships3031### 2. Performance Metrics3233- **Execution Time**: How long operations take34- **Memory Usage**: Peak and average memory consumption35- **CPU Utilization**: Processor usage patterns36- **I/O Wait**: Time spent on I/O operations3738### 3. Optimization Strategies3940- **Algorithmic**: Better algorithms and data structures41- **Implementation**: More efficient code patterns42- **Parallelization**: Multi-threading/processing43- **Caching**: Avoid redundant computation44- **Native Extensions**: C/Rust for critical paths4546## Quick Start4748### Basic Timing4950```python51import time5253def measure_time():54"""Simple timing measurement."""55start = time.time()5657# Your code here58result = sum(range(1000000))5960elapsed = time.time() - start61print(f"Execution time: {elapsed:.4f} seconds")62return result6364# Better: use timeit for accurate measurements65import timeit6667execution_time = timeit.timeit(68"sum(range(1000000))",69number=10070)71print(f"Average time: {execution_time/100:.6f} seconds")72```7374## Profiling Tools7576### Pattern 1: cProfile - CPU Profiling7778```python79import cProfile80import pstats81from pstats import SortKey8283def slow_function():84"""Function to profile."""85total = 086for i in range(1000000):87total += i88return total8990def another_function():91"""Another function."""92return [i**2 for i in range(100000)]9394def main():95"""Main function to profile."""96result1 = slow_function()97result2 = another_function()98return result1, result299100# Profile the code101if __name__ == "__main__":102profiler = cProfile.Profile()103profiler.enable()104105main()106107profiler.disable()108109# Print stats110stats = pstats.Stats(profiler)111stats.sort_stats(SortKey.CUMULATIVE)112stats.print_stats(10) # Top 10 functions113114# Save to file for later analysis115stats.dump_stats("profile_output.prof")116```117118**Command-line profiling:**119120```bash121# Profile a script122python -m cProfile -o output.prof script.py123124# View results125python -m pstats output.prof126# In pstats:127# sort cumtime128# stats 10129```130131### Pattern 2: line_profiler - Line-by-Line Profiling132133```python134# Install: pip install line-profiler135136# Add @profile decorator (line_profiler provides this)137@profile138def process_data(data):139"""Process data with line profiling."""140result = []141for item in data:142processed = item * 2143result.append(processed)144return result145146# Run with:147# kernprof -l -v script.py148```149150**Manual line profiling:**151152```python153from line_profiler import LineProfiler154155def process_data(data):156"""Function to profile."""157result = []158for item in data:159processed = item * 2160result.append(processed)161return result162163if __name__ == "__main__":164lp = LineProfiler()165lp.add_function(process_data)166167data = list(range(100000))168169lp_wrapper = lp(process_data)170lp_wrapper(data)171172lp.print_stats()173```174175### Pattern 3: memory_profiler - Memory Usage176177```python178# Install: pip install memory-profiler179180from memory_profiler import profile181182@profile183def memory_intensive():184"""Function that uses lots of memory."""185# Create large list186big_list = [i for i in range(1000000)]187188# Create large dict189big_dict = {i: i**2 for i in range(100000)}190191# Process data192result = sum(big_list)193194return result195196if __name__ == "__main__":197memory_intensive()198199# Run with:200# python -m memory_profiler script.py201```202203### Pattern 4: py-spy - Production Profiling204205```bash206# Install: pip install py-spy207208# Profile a running Python process209py-spy top --pid 12345210211# Generate flamegraph212py-spy record -o profile.svg --pid 12345213214# Profile a script215py-spy record -o profile.svg -- python script.py216217# Dump current call stack218py-spy dump --pid 12345219```220221## Optimization Patterns222223### Pattern 5: List Comprehensions vs Loops224225```python226import timeit227228# Slow: Traditional loop229def slow_squares(n):230"""Create list of squares using loop."""231result = []232for i in range(n):233result.append(i**2)234return result235236# Fast: List comprehension237def fast_squares(n):238"""Create list of squares using comprehension."""239return [i**2 for i in range(n)]240241# Benchmark242n = 100000243244slow_time = timeit.timeit(lambda: slow_squares(n), number=100)245fast_time = timeit.timeit(lambda: fast_squares(n), number=100)246247print(f"Loop: {slow_time:.4f}s")248print(f"Comprehension: {fast_time:.4f}s")249print(f"Speedup: {slow_time/fast_time:.2f}x")250251# Even faster for simple operations: map252def faster_squares(n):253"""Use map for even better performance."""254return list(map(lambda x: x**2, range(n)))255```256257### Pattern 6: Generator Expressions for Memory258259```python260import sys261262def list_approach():263"""Memory-intensive list."""264data = [i**2 for i in range(1000000)]265return sum(data)266267def generator_approach():268"""Memory-efficient generator."""269data = (i**2 for i in range(1000000))270return sum(data)271272# Memory comparison273list_data = [i for i in range(1000000)]274gen_data = (i for i in range(1000000))275276print(f"List size: {sys.getsizeof(list_data)} bytes")277print(f"Generator size: {sys.getsizeof(gen_data)} bytes")278279# Generators use constant memory regardless of size280```281282### Pattern 7: String Concatenation283284```python285import timeit286287def slow_concat(items):288"""Slow string concatenation."""289result = ""290for item in items:291result += str(item)292return result293294def fast_concat(items):295"""Fast string concatenation with join."""296return "".join(str(item) for item in items)297298def faster_concat(items):299"""Even faster with list."""300parts = [str(item) for item in items]301return "".join(parts)302303items = list(range(10000))304305# Benchmark306slow = timeit.timeit(lambda: slow_concat(items), number=100)307fast = timeit.timeit(lambda: fast_concat(items), number=100)308faster = timeit.timeit(lambda: faster_concat(items), number=100)309310print(f"Concatenation (+): {slow:.4f}s")311print(f"Join (generator): {fast:.4f}s")312print(f"Join (list): {faster:.4f}s")313```314315### Pattern 8: Dictionary Lookups vs List Searches316317```python318import timeit319320# Create test data321size = 10000322items = list(range(size))323lookup_dict = {i: i for i in range(size)}324325def list_search(items, target):326"""O(n) search in list."""327return target in items328329def dict_search(lookup_dict, target):330"""O(1) search in dict."""331return target in lookup_dict332333target = size - 1 # Worst case for list334335# Benchmark336list_time = timeit.timeit(337lambda: list_search(items, target),338number=1000339)340dict_time = timeit.timeit(341lambda: dict_search(lookup_dict, target),342number=1000343)344345print(f"List search: {list_time:.6f}s")346print(f"Dict search: {dict_time:.6f}s")347print(f"Speedup: {list_time/dict_time:.0f}x")348```349350### Pattern 9: Local Variable Access351352```python353import timeit354355# Global variable (slow)356GLOBAL_VALUE = 100357358def use_global():359"""Access global variable."""360total = 0361for i in range(10000):362total += GLOBAL_VALUE363return total364365def use_local():366"""Use local variable."""367local_value = 100368total = 0369for i in range(10000):370total += local_value371return total372373# Local is faster374global_time = timeit.timeit(use_global, number=1000)375local_time = timeit.timeit(use_local, number=1000)376377print(f"Global access: {global_time:.4f}s")378print(f"Local access: {local_time:.4f}s")379print(f"Speedup: {global_time/local_time:.2f}x")380```381382### Pattern 10: Function Call Overhead383384```python385import timeit386387def calculate_inline():388"""Inline calculation."""389total = 0390for i in range(10000):391total += i * 2 + 1392return total393394def helper_function(x):395"""Helper function."""396return x * 2 + 1397398def calculate_with_function():399"""Calculation with function calls."""400total = 0401for i in range(10000):402total += helper_function(i)403return total404405# Inline is faster due to no call overhead406inline_time = timeit.timeit(calculate_inline, number=1000)407function_time = timeit.timeit(calculate_with_function, number=1000)408409print(f"Inline: {inline_time:.4f}s")410print(f"Function calls: {function_time:.4f}s")411```412413For advanced optimization techniques including NumPy vectorization, caching, memory management, parallelization, async I/O, database optimization, and benchmarking tools, see [references/advanced-patterns.md](references/advanced-patterns.md)414415## Best Practices4164171. **Profile before optimizing** - Measure to find real bottlenecks4182. **Focus on hot paths** - Optimize code that runs most frequently4193. **Use appropriate data structures** - Dict for lookups, set for membership4204. **Avoid premature optimization** - Clarity first, then optimize4215. **Use built-in functions** - They're implemented in C4226. **Cache expensive computations** - Use lru_cache4237. **Batch I/O operations** - Reduce system calls4248. **Use generators** for large datasets4259. **Consider NumPy** for numerical operations42610. **Profile production code** - Use py-spy for live systems427428## Common Pitfalls429430- Optimizing without profiling431- Using global variables unnecessarily432- Not using appropriate data structures433- Creating unnecessary copies of data434- Not using connection pooling for databases435- Ignoring algorithmic complexity436- Over-optimizing rare code paths437- Not considering memory usage438