From: ggellner@giton Date: Thu, 23 Oct 2008 03:54:45 +0000 (-0400) Subject: Added special methods info from pyrex, begun documenting the pxd packages X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=df797e1b411f00b20ee040cb180ec852794131c9;p=cython.git Added special methods info from pyrex, begun documenting the pxd packages --- diff --git a/docs/pxd_package.rst b/docs/pxd_package.rst new file mode 100644 index 00000000..7f424b65 --- /dev/null +++ b/docs/pxd_package.rst @@ -0,0 +1,49 @@ +I think this is a result of a recent change to Pyrex that +has been merged into Cython. + +If a directory contains an :file:`__init__.py` or :file:`__init__.pyx` file, +it's now assumed to be a package directory. So, for example, +if you have a directory structure:: + + foo/ + __init__.py + shrubbing.pxd + shrubbing.pyx + +then the shrubbing module is assumed to belong to a package +called 'foo', and its fully qualified module name is +'foo.shrubbing'. + +So when Pyrex wants to find out whether there is a `.pxd` file for shrubbing, +it looks for one corresponding to a module called :module:`foo.shrubbing`. It +does this by searching the include path for a top-level package directory +called 'foo' containing a file called 'shrubbing.pxd'. + +However, if foo is the current directory you're running +the compiler from, and you haven't added foo to the +include path using a -I option, then it won't be on +the include path, and the `.pxd` won't be found. + +What to do about this depends on whether you really +intend the module to reside in a package. + +If you intend shrubbing to be a top-level module, you +will have to move it somewhere else where there is +no :file:`__init__.*` file. + +If you do intend it to reside in a package, then there +are two alternatives: + +1. cd to the directory containing foo and compile + from there:: + + cd ..; cython foo/shrubbing.pyx + +2. arrange for the directory containing foo to be + passed as a -I option, e.g.:: + + cython -I .. shrubbing.pyx + +Arguably this behaviour is not very desirable, and I'll +see if I can do something about it. + diff --git a/docs/pyrex_differences.rst b/docs/pyrex_differences.rst index e07052a3..415e8164 100644 --- a/docs/pyrex_differences.rst +++ b/docs/pyrex_differences.rst @@ -6,11 +6,6 @@ Differences between Cython and Pyrex ************************************** -Package names and cross-directory imports -========================================== - -Just like in python. - List Comprehensions ==================== diff --git a/docs/special_methods.rst b/docs/special_methods.rst new file mode 100644 index 00000000..c4df482e --- /dev/null +++ b/docs/special_methods.rst @@ -0,0 +1,314 @@ +Special Methods of Extension Types +=================================== + +This page describes the special methods currently supported by Pyrex extension +types. A complete list of all the special methods appears in the table at the +bottom. Some of these methods behave differently from their Python +counterparts or have no direct Python counterparts, and require special +mention. + +.. Note: Everything said on this page applies only to extension types, defined + with the :keyword:`cdef class` statement. It doesn't apply to classes defined with the + Python :keyword:`class` statement, where the normal Python rules apply. + +Declaration +------------ +Special methods of extension types must be declared with :keyword:`def`, not +:keyword:`cdef`. + +Docstrings +----------- + +Currently, docstrings are not fully supported in special methods of extension +types. You can place a docstring in the source to serve as a comment, but it +won't show up in the corresponding :attr:`__doc__` attribute at run time. (This is a +Python limitation -- there's nowhere in the `PyTypeObject` data structure to put +such docstrings.) + +Initialisation methods: :meth:`__cinit__` and :meth:`__init__` +--------------------------------------------------------------- +There are two methods concerned with initialising the object. + +The :meth:`__cinit__` method is where you should perform basic C-level +initialisation of the object, including allocation of any C data structures +that your object will own. You need to be careful what you do in the +:meth:`__cinit__` method, because the object may not yet be a valid Python +object when it is called. Therefore, you must not invoke any Python operations +which might touch the object; in particular, do not try to call any of its +methods. + +By the time your :meth:`__cinit__` method is called, memory has been allocated for the +object and any C attributes it has have been initialised to 0 or null. (Any +Python attributes have also been initialised to None, but you probably +shouldn't rely on that.) Your :meth:`__cinit__` method is guaranteed to be called +exactly once. + +If your extension type has a base type, the :meth:`__cinit__` method of the base type +is automatically called before your :meth:`__cinit__` method is called; you cannot +explicitly call the inherited :meth:`__cinit__` method. If you need to pass a modified +argument list to the base type, you will have to do the relevant part of the +initialisation in the :meth:`__init__` method instead (where the normal rules for +calling inherited methods apply). + +Any initialisation which cannot safely be done in the :meth:`__cinit__` method should +be done in the :meth:`__init__` method. By the time :meth:`__init__` is called, the object is +a fully valid Python object and all operations are safe. Under some +circumstances it is possible for :meth:`__init__` to be called more than once or not +to be called at all, so your other methods should be designed to be robust in +such situations. + +Any arguments passed to the constructor will be passed to both the +:meth:`__cinit__` method and the :meth:`__init__` method. If you anticipate +subclassing your extension type in Python, you may find it useful to give the +:meth:`__cinit__` method `*` and `**` arguments so that it can accept and +ignore extra arguments. Otherwise, any Python subclass which has an +:meth:`__init__` with a different signature will have to override +:meth:`__new__` as well as :meth:`__init__`, which the writer of a Python +class wouldn't expect to have to do. Finalization method: :meth:`__dealloc__` +The counterpart to the :meth:`__cinit__` method is the :meth:`__dealloc__` +method, which should perform the inverse of the :meth:`__cinit__` method. Any +C data structures that you allocated in your :meth:`__cinit__` method should +be freed in your :meth:`__dealloc__` method. + +You need to be careful what you do in a :meth:`__dealloc__` method. By the time your +:meth:`__dealloc__` method is called, the object may already have been partially +destroyed and may not be in a valid state as far as Python is concerned, so +you 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 which +might cause the object to be resurrected. It's best if you stick to just +deallocating C data. + +You don't need to worry about deallocating Python attributes of your object, +because that will be done for you by Pyrex after your :meth:`__dealloc__` method +returns. + +.. Note: There is no :meth:`__del__` method for extension types. + +Arithmetic methods +------------------- + +Arithmetic operator methods, such as :meth:`__add__`, behave differently from their +Python counterparts. There are no separate "reversed" versions of these +methods (:meth:`__radd__`, etc.) Instead, if the first operand cannot perform the +operation, the same method of the second operand is called, with the operands +in the same order. + +This means that you can't rely on the first parameter of these methods being +"self", and you should test the types of both operands before deciding what to +do. If you can't handle the combination of types you've been given, you should +return `NotImplemented`. + +This also applies to the in-place arithmetic method :meth:`__ipow__`. It doesn't apply +to any of the other in-place methods (:meth:`__iadd__`, etc.) which always +take `self` as the first argument. + +Rich comparisons +----------------- + +There are no separate methods for the individual rich comparison operations +(:meth:`__eq__`, :meth:`__le__`, etc.) Instead there is a single method +:meth:`__richcmp__` which takes an integer indicating which operation is to be +performed, as follows: + ++-----+-----+ +| < | 0 | ++-----+-----+ +| == | 2 | ++-----+-----+ +| > | 4 | ++-----+-----+ +| <= | 1 | ++-----+-----+ +| != | 3 | ++-----+-----+ +| >= | 5 | ++-----+-----+ + +The :meth:`__next__` method +---------------------------- + +Extension types wishing to implement the iterator interface should define a +method called :meth:`__next__`, not next. The Python system will automatically +supply a next method which calls your :meth:`__next__`. Do *NOT* explicitly +give your type a next method, or bad things could happen. + +Type Testing in Special Methods +-------------------------------- + +.. TODO document the Cython way using the overridden isinstance + + +Special Method 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. + ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| Name | Parameters | Return type | Description | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| General | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __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 | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __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 | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __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 | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __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 | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __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 | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __next__ | self | object | Get next item (called next in Python) | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| Buffer interface (no Python equivalents - see note 1) | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __getreadbuffer__ | self, int i, void `**p` | | | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __getwritebuffer__ | self, int i, void `**p` | | | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __getsegcount__ | self, int `*p` | | | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __getcharbuffer__ | self, int i, char `**p` | | | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| Descriptor objects (see note 2) | ++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +| __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 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. + +.. note:: (2) 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". + diff --git a/index.rst b/index.rst index 4c14c1cd..e513f1e2 100644 --- a/index.rst +++ b/index.rst @@ -12,6 +12,7 @@ Contents: docs/numpy_tutorial docs/language_basics docs/extension_types + docs/special_methods docs/sharing_declarations docs/external_C_code docs/source_files_and_compilation diff --git a/sphinxext/cython_highlighting.pyc b/sphinxext/cython_highlighting.pyc index 9ae12f81..e026e9eb 100644 Binary files a/sphinxext/cython_highlighting.pyc and b/sphinxext/cython_highlighting.pyc differ diff --git a/sphinxext/ipython_console_highlighting.pyc b/sphinxext/ipython_console_highlighting.pyc index efcf6e02..4c0dea0f 100644 Binary files a/sphinxext/ipython_console_highlighting.pyc and b/sphinxext/ipython_console_highlighting.pyc differ