From e5f8b65cb83c60b385b8d4ab17028cde4ccbf71b Mon Sep 17 00:00:00 2001 From: Peter Alexander Date: Tue, 6 Oct 2009 19:19:08 -0400 Subject: [PATCH] more work on extension types --- src/reference/extension_types.rst | 186 +++++++++++++++++++- src/reference/index.rst | 5 + src/reference/special_methods_table.rst | 216 ++++++++++++++++++++++++ 3 files changed, 402 insertions(+), 5 deletions(-) create mode 100644 src/reference/special_methods_table.rst diff --git a/src/reference/extension_types.rst b/src/reference/extension_types.rst index 190e733b..6935bf94 100644 --- a/src/reference/extension_types.rst +++ b/src/reference/extension_types.rst @@ -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 ====== diff --git a/src/reference/index.rst b/src/reference/index.rst index 4c02cc08..628e7ee7 100644 --- a/src/reference/index.rst +++ b/src/reference/index.rst @@ -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 index 00000000..8608be3f --- /dev/null +++ b/src/reference/special_methods_table.rst @@ -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 | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ + + + + + -- 2.26.2