Commit e5f8b65c authored by Peter Alexander's avatar Peter Alexander

more work on extension types

parent 70816c16
......@@ -12,7 +12,9 @@ Extention Types
* Are considered by Python to be "built-in" types.
* Can be used to wrap arbitrary C data structures, and provide a Python-like interface to them from Python.
* Attributes and methods can be called from Python or Cython code
* Are defined by the ``cdef`` class statement::
* Are defined by the ``cdef class`` statement.
::
cdef class Shrubbery:
......@@ -104,9 +106,9 @@ Properties
* Below, is a full example that defines a property which can..
* Add to a list each time it is written to.
* Return the list when it is read.
* Empty the list when it is deleted.
* Add to a list each time it is written to (``"__set__"``).
* Return the list when it is read (``"__get__"``).
* Empty the list when it is deleted (``"__del__"``).
::
......@@ -157,16 +159,180 @@ Properties
Special Methods
===============
.. provide link to the table of special methods
.. note:: Attention
The semantics of special methods are similar in principle to Python, but there are substantial differences in some behavior.
* See :doc:`special_methods_table` for available methods.
* Cython provides many "special method" method types.
* Be aware that some Cython special methods have no Python counter-part.
Declaration
===========
* Must be declared with ``def`` and cannot be declared with ``cdef``.
* Performance is not affected by the ``def`` declaration because of special calling conventions
Docstrings
==========
* Docstrings are not supported yet for some special method types.
* They can be included in the source, but may not appear in the corresponding ``__doc__`` attribute at run-time.
* This a Python library limitation because the ``PyTypeObject`` data structure is limited
Initialization: ``__cinit__()`` and ``__init__()``
==================================================
* Any arguments passed to the extension type's constructor, will be passed to both initialization methods.
* ``__cinit__()`` is where you should perform C-level initialization of the object
* This includes any allocation of C data structures.
* **Caution** is warranted as to what you do in this method.
* The object may not be fully valid Python object when it is called.
* Calling Python objects, including the extensions own methods, may be hazardous.
* By the time ``__cinit__()`` is called...
* Memory has been allocated for the object.
* All C-level attributes have been initialized to 0 or null.
* Python have been initialized to ``None``, but you can not rely on that for each occasion.
* This initialization method is guaranteed to be called exactly once.
* For Extensions types that inherit a base type:
* The ``__cinit__()`` method of the base type is automatically called before this one.
* The inherited ``__cinit__()`` method can not be called explicitly.
* Passing modified argument lists to the base type must be done through ``__init__()``.
* It may be wise to give the ``__cinit__()`` method both ``"*"`` and ``"**"`` arguments.
* Allows the method to accept or ignore additional arguments.
* Eliminates the need for a Python level sub-class, that changes the ``__init__()`` method's signature, to have to override both the ``__new__()`` and ``__init__()`` methods.
* If ``__cinit__()`` is declared to take no arguments except ``self``, it will ignore any extra arguments passed to the constructor without complaining about a signature mis-match
* ``__init__()`` is for higher-level initialization and is safer for Python access.
* By the time this method is called, the extension type is a fully valid Python object.
* All operations are safe.
* This method may sometimes be called more than once, or possibly not at all.
* Take this into consideration to make sure the design of your other methods are robust of this fact.
Finalization: ``__dealloc__()``
===============================
* This method is the counter-part to ``__cinit__()``.
* Any C-data that was explicitly allocated in the ``__cinit__()`` method should be freed here.
* Use caution in this method:
* The Python object to which this method belongs may not be completely intact at this point.
* Avoid invoking any Python operations that may touch the object.
* Don't call any of this object's methods.
* It's best to just deallocate C-data structures here.
* All Python attributes of your extension type object are deallocated by Cython after the ``__dealloc__()`` method returns.
Arithmetic Methods
==================
.. note:: Most of these methods behave differently than in Python
* There are not "reversed" versions of these methods... there is no __radd__() for instance.
* If the first operand cannot perform the operation, the same method of the second operand is called, with the operands in the same order.
* Do not rely on the first parameter of these methods, being ``"self"`` or the right type.
* The types of both operands should be tested before deciding what to do.
* Return ``NotImplemented`` for unhandled, mis-matched operand types.
* The previously mentioned points..
* Also apply to 'in-place' method ``__ipow__()``.
* Do not apply to other 'in-place' methods like ``__iadd__()``, in that these always take ``self`` as the first argument.
Rich Comparisons
================
.. note:: There are no separate methods for individual rich comparison operations.
* A single special method called ``__richcmp__()`` replaces all the individual rich compare, special method types.
* ``__richcmp__()`` takes an integer argument, indicating which operation is to be performed as shown in the table below.
+-----+-----+
| < | 0 |
+-----+-----+
| == | 2 |
+-----+-----+
| > | 4 |
+-----+-----+
| <= | 1 |
+-----+-----+
| != | 3 |
+-----+-----+
| >= | 5 |
+-----+-----+
The ``__next__()`` Method
=========================
* Extension types used to expose an iterator interface should define a ``__next__()`` method.
* **Do not** explicitly supply a ``next()`` method, because Python does that for you automatically.
===========
Subclassing
===========
* An extension type may inherit from a built-in type or another extension type::
cdef class Parrot:
...
cdef class Norwegian(Parrot):
...
* A complete definition of the base type must be available to Cython
* If the base type is a built-in type, it must have been previously declared as an ``extern`` extension type.
* ``cimport`` can be used to import the base type, if the extern declared base type is in a ``.pxd`` definition file.
* In Cython, multiple inheritance is not permitted.. singlular inheritance only
* Cython extenstion types can also be sub-classed in Python.
* Here multiple inhertance is permissible as is normal for Python.
* Even multiple extension types may be inherited, but C-layout of all the base classes must be compatible.
====================
Forward Declarations
====================
* Extension types can be "forward-declared".
* This is necessary when two extension types refer to each other::
cdef class Shrubbery # forward declaration
cdef class Shrubber:
cdef Shrubbery work_in_progress
cdef class Shrubbery:
cdef Shrubber creator
* An extension type that has a base-class, requires that both forward-declarations be specified::
cdef class A(B)
...
cdef class A(B):
# attributes and methods
========================
Extension Types and None
========================
......@@ -175,6 +341,16 @@ Extension Types and None
Weak Referencing
================
* By default, weak references are not supported.
* It can be enabled by declaring a C attribute of the ``object`` type called ``__weakref__()``::
cdef class ExplodingAnimal:
"""This animal will self-destruct when it is
no longer strongly referenced."""
cdef object __weakref__
======
Public
======
......
......@@ -20,6 +20,11 @@ Contents:
Indices and tables
------------------
.. toctree::
:maxdepth: 2
special_methods_table
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Special Methods Table
---------------------
This table lists all of the special methods together with their parameter and
return types. In the table below, a parameter name of self is used to indicate
that the parameter has the type that the method belongs to. Other parameters
with no type specified in the table are generic Python objects.
You don't have to declare your method as taking these parameter types. If you
declare different types, conversions will be performed as necessary.
General
^^^^^^^
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| 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 |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __richcmp__ |x, y, int op | object | Rich comparison (no direct Python equivalent) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __str__ |self | object | str(self) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __repr__ |self | object | repr(self) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __hash__ |self | int | Hash function |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __call__ |self, ... | object | self(...) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __iter__ |self | object | Return iterator for sequence |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __getattr__ |self, name | object | Get attribute |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __setattr__ |self, name, val | | Set attribute |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __delattr__ |self, name | | Delete attribute |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
Arithmetic operators
^^^^^^^^^^^^^^^^^^^^
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| 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
^^^^^^^^^^^^^^^^^^^
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| 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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| 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
^^^^^^^^^^^^^^^^^^^^^^
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| Name | Parameters | Return type | Description |
+=======================+=======================================+=============+=====================================================+
| __len__ | self int | | len(self) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __getitem__ | self, x | object | self[x] |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __setitem__ | self, x, y | | self[x] = y |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __delitem__ | self, x | | del self[x] |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __getslice__ | self, Py_ssize_t i, Py_ssize_t 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
^^^^^^^^^
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| Name | Parameters | Return type | Description |
+=======================+=======================================+=============+=====================================================+
| __next__ | self | object | Get next item (called next in Python) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
Buffer interface
^^^^^^^^^^^^^^^^
.. note::
The buffer interface is intended for use by C code and is not directly
accessible from Python. It is described in the Python/C API Reference Manual
under sections 6.6 and 10.6.
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| Name | Parameters | Return type | Description |
+=======================+=======================================+=============+=====================================================+
| __getreadbuffer__ | self, int i, void `**p` | | |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __getwritebuffer__ | self, int i, void `**p` | | |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __getsegcount__ | self, int `*p` | | |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __getcharbuffer__ | self, int i, char `**p` | | |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
Descriptor objects
^^^^^^^^^^^^^^^^^^
.. note::
Descriptor objects are part of the support mechanism for new-style
Python 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".
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| 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 |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment