more work on extension types
authorPeter Alexander <vel.accel@gmail.com>
Tue, 6 Oct 2009 23:19:08 +0000 (19:19 -0400)
committerPeter Alexander <vel.accel@gmail.com>
Tue, 6 Oct 2009 23:19:08 +0000 (19:19 -0400)
src/reference/extension_types.rst
src/reference/index.rst
src/reference/special_methods_table.rst [new file with mode: 0644]

index 190e733b87b7b2b1e71c20ac27dd3152e261d828..6935bf94578558e10e65cfe0b318fa2ed824d15f 100644 (file)
@@ -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
 ======
index 4c02cc0853192f75c9dc5646eaa98f7dde942f49..628e7ee724deb11a8ff8a64d02f9a5632ae5ae75 100644 (file)
@@ -20,6 +20,11 @@ Contents:
 Indices and tables
 ------------------
 
+.. toctree::
+    :maxdepth: 2
+
+    special_methods_table
+
 * :ref:`genindex`
 * :ref:`modindex`
 * :ref:`search`
diff --git a/src/reference/special_methods_table.rst b/src/reference/special_methods_table.rst
new file mode 100644 (file)
index 0000000..8608be3
--- /dev/null
@@ -0,0 +1,216 @@
+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                                |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+
+
+
+