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`
This diff is collapsed.
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