Shed Skin can compile Python code into extension modules that can be imported and used in regular Python programs. This allows you to accelerate performance-critical parts of your application while keeping the rest in Python.
Understanding Extension Modules
An extension module is a compiled shared library (.so on Linux/macOS, .pyd on Windows) that Python can import like any other module. Shed Skin-generated extension modules provide:
- Massive speedups (typically 10-100x) for computation-intensive code
- Seamless integration with existing Python codebases
- No changes to calling code - import and use normally
Use extension modules when you have performance bottlenecks in pure computation code that doesn’t heavily rely on external libraries.
Creating Your First Extension Module
Real-World Example
Let’s accelerate a prime sieve computation:
Compile it:
Use it in your main program:
Extension Module Limitations
Extension modules have important restrictions compared to pure Python.
Supported Types
Only these types can be passed across the Python/C++ boundary:
Builtin types:
- Scalars:
int, float, complex, bool, str, bytes, bytearray
- Collections:
list, tuple, dict, set
- Special:
None
- User-defined class instances
Not supported:
- Functions/lambdas
- Generators/iterators
- File objects
- Module objects
Data Conversion Overhead
Builtin types are completely converted on each call/return. This means:
- Large data structures have conversion overhead
- Changes to builtin objects don’t persist across the boundary
- User-defined class instances pass by reference (no conversion)
Global Variable Behavior
Global variables are converted once at initialization. Changes in Python don’t affect the extension module and vice versa.
Using with NumPy
While Shed Skin doesn’t support NumPy directly, you can pass arrays as lists:
Compile and use with NumPy:
Conversion with .tolist() is expensive. Only worthwhile if significant computation happens inside the extension module.
Multiprocessing Integration
Extension modules work great with Python’s multiprocessing:
Compile:
Use with multiprocessing:
Distribution and Deployment
Best Practices
Keep the interface simple: Pass basic types, return basic types. Use user classes for complex data.
Profile first: Ensure the code is actually a bottleneck before creating an extension module.
Minimize data transfer: Design functions that do significant work per call to amortize conversion overhead.
Test both versions: Keep the Python version and test that both produce identical results.
Troubleshooting
Import fails:
Type inference fails:
Segmentation fault:
- Likely a type mismatch between Python and C++
- Review None handling (only with non-scalars)
- Check array/list bounds
See the Optimization guide for detailed performance tuning of extension modules.