Cython cdef vs cpdef vs def Syntax Differences
Cython provides three distinct function declaration
keywords—def, cdef, and
cpdef—which control how functions are compiled, where they
can be accessed, and how efficiently they execute. Understanding the
differences among these keywords allows developers to balance execution
speed with Python interoperability. This guide outlines the syntax,
accessibility, performance implications, and practical use cases for
each function type in Cython.
Quick Comparison
| Feature | def |
cdef |
cpdef |
|---|---|---|---|
| Callable from Python? | Yes | No | Yes |
| Callable from Cython/C? | Yes | Yes | Yes |
| Return/Argument Types | Python objects (or auto-coerced) | C types and Python objects | C types and Python objects |
| Call Overhead | High (Python standard) | Minimal (Pure C call) | Minimal via Cython; High via Python |
| Primary Use Case | Public Python API | Internal, performance-critical tasks | Hybrid public/private functions |
1. The def Function
The def statement declares a standard Python function.
It produces a regular Python function object that is placed into the
module's namespace and can be invoked directly from pure Python
code.
Syntax
def add_py(int a, int b):
return a + b
Characteristics
- Visibility: Accessible from both Python and Cython modules.
- Typing: Parameter types can be statically typed
using C-types (like
int a), but the function always accepts and returns Python objects under the hood. Cython handles the conversion (boxing and unboxing) of arguments and return values. - Performance: Suffers from standard Python function call overhead. It is not suitable for inner loops where call overhead dominates run time.
2. The cdef Function
The cdef statement defines a pure C-level function. It
cannot be accessed directly from pure Python code because it is not
exported to the Python module’s symbol table.
Syntax
cdef int add_c(int a, int b):
return a + b
Characteristics
- Visibility: Only callable from Cython code within
the same compilation unit or via
.pxdheader files. It is invisible to pure Python. - Typing: Can accept and return arbitrary C types
(including raw pointers, structs, and unions) in addition to Python
objects. The return type is declared immediately after
cdef. - Performance: Executes with native C speed and near-zero function call overhead. It is ideal for internal helper functions, mathematical operations, and tight loops.
3. The cpdef Function
The cpdef keyword creates a hybrid function. The Cython
compiler generates two versions: a fast C-level function and a
lightweight Python wrapper that forwards arguments to the C
function.
Syntax
cpdef int add_hybrid(int a, int b):
return a + b
Characteristics
- Visibility: Fully accessible from both pure Python and Cython.
- Typing: Requires types that Cython knows how to
convert to and from Python objects. C pointers, C unions, or C++
references cannot be used in the signature of a
cpdeffunction. - Performance: When called from Cython, it bypasses Python's runtime and calls the underlying C function directly for native speed. When called from Python, it introduces the standard wrapper overhead.
Summary of Syntax Rules
- Return Types:
defdoes not allow an explicit C return type before the function name (e.g.,def int func():is invalid).cdefandcpdefrequire or allow a C return type directly after the keyword (e.g.,cdef double compute():orcpdef void process():).
- Type Compatibility:
- Use
cdefif you need to use non-Python-compatible types (like raw memory pointers:int*). - Use
cpdefif you want maximum speed in Cython while keeping the function accessible to standard Python scripts. - Use
defwhen creating external module interfaces that do not benefit from C-level internal calls.
- Use