Special Methods of Extension Types
This page describes the special methods currently supported by Cython extensiontypes. A complete list of all the special methods appears in the table at thebottom. Some of these methods behave differently from their Pythoncounterparts or have no direct Python counterparts, and require specialmention.
Note
Everything said on this page applies only to extension types, definedwith the cdef class
statement. It doesn’t apply to classes defined with thePython class
statement, where the normal Python rules apply.
Declaration
Special methods of extension types must be declared with def
, notcdef
. This does not impact their performance–Python uses differentcalling conventions to invoke these special methods.
Docstrings
Currently, docstrings are not fully supported in some special methods of extensiontypes. You can place a docstring in the source to serve as a comment, but itwon’t show up in the corresponding doc
attribute at run time. (Thisseems to be is a Python limitation – there’s nowhere in the _PyTypeObject_data structure to put such docstrings.)
Initialisation methods: cinit() and init()
There are two methods concerned with initialising the object.
The cinit()
method is where you should perform basic C-levelinitialisation of the object, including allocation of any C data structuresthat your object will own. You need to be careful what you do in thecinit()
method, because the object may not yet be a fully valid Pythonobject when it is called. Therefore, you should be careful invoking any Pythonoperations which might touch the object; in particular, its methods and anythingthat could be overridden by subtypes (and thus depend on their subtype state beinginitialised already).
By the time your cinit()
method is called, memory has been allocated for theobject and any C attributes it has have been initialised to 0 or null. (AnyPython attributes have also been initialised to None, but you probablyshouldn’t rely on that.) Your cinit()
method is guaranteed to be calledexactly once.
If your extension type has a base type, any existing cinit()
methods inthe base type hierarchy are automatically called before your cinit()
method. You cannot explicitly call the inherited cinit()
methods, and thebase types are free to choose whether they implement cinit()
at all.If you need to pass a modified argument list to the base type, you will have to dothe relevant part of the initialisation in the init()
method instead, wherethe normal rules for calling inherited methods apply.
Any initialisation which cannot safely be done in the cinit()
method shouldbe done in the init()
method. By the time init()
is called, the object isa fully valid Python object and all operations are safe. Under somecircumstances it is possible for init()
to be called more than once or notto be called at all, so your other methods should be designed to be robust insuch situations.
Any arguments passed to the constructor will be passed to both thecinit()
method and the init()
method. If you anticipatesubclassing your extension type in Python, you may find it useful to give thecinit()
method * and ** arguments so that it can accept andignore extra arguments. Otherwise, any Python subclass which has aninit()
with a different signature will have to overridenew()
[1] as well as init()
, which the writer of a Pythonclass wouldn’t expect to have to do. Alternatively, as a convenience, if you declareyour cinit`()
method to take no arguments (other than self) itwill simply ignore any extra arguments passed to the constructor withoutcomplaining about the signature mismatch.
Note
All constructor arguments will be passed as Python objects.This implies that non-convertible C types such as pointers or C++ objectscannot be passed into the constructor from Cython code. If this is needed,use a factory function instead that handles the object initialisation.It often helps to directly call new()
in this function to bypass thecall to the init()
constructor.
See Instantiation from existing C/C++ pointers for an example.
[1] | https://docs.python.org/reference/datamodel.html#object.new |
Finalization method: dealloc()
The counterpart to the cinit()
method is the dealloc()
method, which should perform the inverse of the cinit()
method. AnyC data that you explicitly allocated (e.g. via malloc) in yourcinit()
method should be freed in your dealloc()
method.
You need to be careful what you do in a dealloc()
method. By the time yourdealloc()
method is called, the object may already have been partiallydestroyed and may not be in a valid state as far as Python is concerned, soyou should avoid invoking any Python operations which might touch the object.In particular, don’t call any other methods of the object or do anything whichmight cause the object to be resurrected. It’s best if you stick to justdeallocating C data.
You don’t need to worry about deallocating Python attributes of your object,because that will be done for you by Cython after your dealloc()
methodreturns.
When subclassing extension types, be aware that the dealloc()
methodof the superclass will always be called, even if it is overridden. This is incontrast to typical Python behavior where superclass methods will not beexecuted unless they are explicitly called by the subclass.
Note
There is no del()
method for extension types.
Arithmetic methods
Arithmetic operator methods, such as add()
, behave differently from theirPython counterparts. There are no separate “reversed” versions of thesemethods (radd()
, etc.) Instead, if the first operand cannot perform theoperation, the same method of the second operand is called, with the operandsin the same order.
This means that you can’t rely on the first parameter of these methods being“self” or being the right type, and you should test the types of both operandsbefore deciding what to do. If you can’t handle the combination of types you’vebeen given, you should return NotImplemented.
This also applies to the in-place arithmetic method ipow()
. It doesn’t applyto any of the other in-place methods (iadd()
, etc.) which alwaystake self as the first argument.
Rich comparisons
There are two ways to implement comparison methods.Depending on the application, one way or the other may be better:
The first way uses the 6 Pythonspecial methods
eq()
,lt()
, etc.This is new since Cython 0.27 and works exactly as in plain Python classes.The second way uses a single special method
richcmp()
.This implements all rich comparison operations in one method.The signature isdef richcmp(self, other, int op)
.The integer argumentop
indicates which operation is to be performedas shown in the table below:
These constants can be cimported from the cpython.object
module.
The next() method
Extension types wishing to implement the iterator interface should define amethod called next()
, not next. The Python system will automaticallysupply a next method which calls your next()
. Do NOT explicitlygive your type a next()
method, or bad things could happen.
Special Method Table
This table lists all of the special methods together with their parameter andreturn types. In the table below, a parameter name of self is used to indicatethat the parameter has the type that the method belongs to. Other parameterswith no type specified in the table are generic Python objects.
You don’t have to declare your method as taking these parameter types. If youdeclare different types, conversions will be performed as necessary.
General
https://docs.python.org/3/reference/datamodel.html#special-method-names
Name | Parameters | Return type | Description |
---|---|---|---|
cinit | self, … | Basic initialisation (no direct Python equivalent) | |
init | self, … | Further initialisation | |
dealloc | self | Basic deallocation (no direct Python equivalent) | |
cmp | x, y | int | 3-way comparison (Python 2 only) |
str | self | object | str(self) |
repr | self | object | repr(self) |
hash | self | Pyhasht | Hash function (returns 32/64 bit integer) |
call | self, … | object | self(…) |
iter | self | object | Return iterator for sequence |
getattr | self, name | object | Get attribute |
getattribute | self, name | object | Get attribute, unconditionally |
setattr | self, name, val | Set attribute | |
__delattr | self, name | Delete attribute |
Rich comparison operators
https://docs.python.org/3/reference/datamodel.html#basic-customization
You can choose to either implement the standard Python special methodslike eq()
or the single special method richcmp()
.Depending on the application, one way or the other may be better.
Name | Parameters | Return type | Description |
---|---|---|---|
eq | self, y | object | self == y |
ne | self, y | object | self != y (falls back to eq if not available) |
lt | self, y | object | self < y |
gt | self, y | object | self > y |
le | self, y | object | self <= y |
ge | self, y | object | self >= y |
richcmp | self, y, int op | object | Joined rich comparison method for all of the above(no direct Python equivalent) |
Arithmetic operators
https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
Name | Parameters | Return type | Description |
---|---|---|---|
add | x, y | object | binary + operator |
sub | x, y | object | binary - operator |
mul | x, y | object | * operator |
div | x, y | object | / operator for old-style division |
floordiv | x, y | object | // operator |
truediv | x, y | object | / operator for new-style division |
mod | x, y | object | % operator |
divmod | x, y | object | combined div and mod |
pow | x, y, z | object | ** operator or pow(x, y, z) |
neg | self | object | unary - operator |
pos | self | object | unary + operator |
abs | self | object | absolute value |
nonzero | self | int | convert to boolean |
invert | self | object | ~ operator |
lshift | x, y | object | << operator |
rshift | x, y | object | >> operator |
and | x, y | object | & operator |
or | x, y | object | | operator |
xor | x, y | object | ^ operator |
Numeric conversions
https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
Name | Parameters | Return type | Description |
---|---|---|---|
int | self | object | Convert to integer |
long | self | object | Convert to long integer |
float | self | object | Convert to float |
oct | self | object | Convert to octal |
hex | self | object | Convert to hexadecimal |
index (2.5+ only) | self | object | Convert to sequence index |
In-place arithmetic operators
https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
Name | Parameters | Return type | Description |
---|---|---|---|
iadd | self, x | object | += operator |
isub | self, x | object | -= operator |
imul | self, x | object | *= operator |
idiv | self, x | object | /= operator for old-style division |
ifloordiv | self, x | object | //= operator |
itruediv | self, x | object | /= operator for new-style division |
imod | self, x | object | %= operator |
ipow | x, y, z | object | **= operator |
ilshift | self, x | object | <<= operator |
irshift | self, x | object | >>= operator |
iand | self, x | object | &= operator |
ior | self, x | object | |= operator |
ixor | self, x | object | ^= operator |
Sequences and mappings
https://docs.python.org/3/reference/datamodel.html#emulating-container-types
Name | Parameters | Return type | Description |
---|---|---|---|
len | self | Pyssizet | len(self) |
getitem | self, x | object | self[x] |
setitem | self, x, y | self[x] = y | |
delitem | self, x | del self[x] | |
getslice | self, Pyssizet i, Pyssizet j | object | self[i:j] |
__setslice | self, Py_ssize_t i, Py_ssize_t j, x | self[i:j] = x | |
__delslice | self, Py_ssize_t i, Py_ssize_t j | del self[i:j] | |
__contains | self, x | int | x in self |
Iterators
https://docs.python.org/3/reference/datamodel.html#emulating-container-types
Name | Parameters | Return type | Description |
---|---|---|---|
next | self | object | Get next item (called next in Python) |
Buffer interface [PEP 3118] (no Python equivalents - see note 1)
Name | Parameters | Return type | Description |
---|---|---|---|
getbuffer | self, Pybuffer view, int flags | ||
releasebuffer | self, Py_buffer view_ |
Buffer interface [legacy] (no Python equivalents - see note 1)
Name | Parameters | Return type | Description |
---|---|---|---|
getreadbuffer | self, Pyssize_t i, void p | ||
getwritebuffer | self, Py_ssize_t i, void p | ||
getsegcount | self, Py_ssize_t p | ||
getcharbuffer | self, Py_ssize_t i, char *p_ |
Descriptor objects (see note 2)
https://docs.python.org/3/reference/datamodel.html#emulating-container-types
Name | Parameters | Return type | Description |
---|---|---|---|
get | self, instance, class | object | Get value of attribute |
set | self, instance, value | Set value of attribute | |
delete | self, instance | Delete attribute |
Note
(1) The buffer interface was intended for use by C code and is not directlyaccessible from Python. It is described in the Python/C API Reference Manualof Python 2.x under sections 6.6 and 10.6. It was superseded by the newPEP 3118 buffer protocol in Python 2.6 and is no longer available in Python 3.For a how-to guide to the new API, see Implementing the buffer protocol.
Note
(2) Descriptor objects are part of the support mechanism for new-stylePython classes. See the discussion of descriptors in the Python documentation.See also PEP 252, “Making Types Look More Like Classes”, and PEP 253,“Subtyping Built-In Types”.