Commit 01f291a8 authored by Stefan Behnel's avatar Stefan Behnel

Rewrite the section that describes the differences between __cinit__() and...

Rewrite the section that describes the differences between __cinit__() and __init__(), to make it clearer when to use which.
parent 2a304b0f
......@@ -34,67 +34,80 @@ won't show up in the corresponding :attr:`__doc__` attribute at run time. (This
seems to be is a Python limitation -- there's nowhere in the `PyTypeObject`
data structure to put such docstrings.)
.. _initialisation_methods:
Initialisation methods: :meth:`__cinit__` and :meth:`__init__`
---------------------------------------------------------------
There are two methods concerned with initialising the object.
There are two methods concerned with initialising the object, the normal Python
:meth:`__init__` method and a special :meth:`__cinit__` method where basic
C level initialisation can be performed.
The main difference between the two is when they are called.
The :meth:`__cinit__` method is guaranteed to be called as part of the object
allocation, but before the object is fully initialised. Specifically, methods
and object attributes that belong to subclasses or that were overridden by
subclasses may not have been initialised at all yet and must not be used by
:meth:`__cinit__` in a base class. Note that the object allocation in Python
clears all fields and sets them to zero (or ``NULL``). Cython additionally
takes responsibility of setting all object attributes to ``None``, but again,
this may not yet have been done for the attributes defined or overridden by
subclasses. If your object needs anything more than this basic attribute
clearing in order to get into a correct and safe state, :meth:`__cinit__`
may be a good place to do it.
The :meth:`__init__` method, on the other hand, works exactly like in Python.
It is called after allocation and basic initialisation of the object, including
the complete inheritance chain.
By the time :meth:`__init__` is called, the object is a fully valid Python object
and all operations are safe. Any initialisation which cannot safely be done in
the :meth:`__cinit__` method should be done in the :meth:`__init__` method.
However, as in Python, it is the responsibility of the subclasses to call up the
hierarchy and make sure that the :meth:`__init__` methods in the base class are
called correctly. If a subclass forgets (or refuses) to call the :meth:`__init__`
method of one of its base classes, that method will not be called.
Also, if the object gets created by calling directly its :meth:`__new__` method
(as opposed to calling the class itself), then none of the :meth:`__init__`
methods will be called.
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 fully valid Python
object when it is called. Therefore, you should be careful invoking any Python
operations which might touch the object; in particular, its methods and anything
that could be overridden by subtypes (and thus depend on their subtype state being
initialised already).
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.
initialisation of the object, possibly including allocation of any C data
structures that your object will own. In contrast to :meth:`__init__`,
your :meth:`__cinit__` method is guaranteed to be called exactly once.
If your extension type has a base type, any existing :meth:`__cinit__` methods in
the base type hierarchy are automatically called before your :meth:`__cinit__`
method. You cannot explicitly call the inherited :meth:`__cinit__` methods, and the
base types are free to choose whether they implement :meth:`__cinit__` at all.
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.
the relevant part of the initialisation in the :meth:`__init__` method instead,
where the normal rules for calling inherited methods apply.
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
subclassing your extension type, 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. Alternatively, as a convenience, if you declare
your :meth:`__cinit__`` method to take no arguments (other than self) it
will simply ignore any extra arguments passed to the constructor without
complaining about the signature mismatch.
ignore arbitrary extra arguments, since the arguments that are passed through
the hierarchy during allocation cannot be changed by subclasses.
Alternatively, as a convenience, if you declare your :meth:`__cinit__`` method
to take no arguments (other than self) it will simply ignore any extra arguments
passed to the constructor without complaining about the signature mismatch.
.. Note::
All constructor arguments will be passed as Python objects.
This implies that non-convertible C types such as pointers or C++ objects
cannot be passed into the constructor from Cython code. If this is needed,
use a factory function instead that handles the object initialisation.
It often helps to directly call ``__new__()`` in this function to bypass the
call to the ``__init__()`` constructor.
cannot be passed into the constructor, neither from Python nor from Cython code.
If this is needed, use a factory function or method instead that handles the
object initialisation.
It often helps to directly call the :meth:`__new__` method in this function to
explicitly bypass the call to the :meth:`__init__` constructor.
See :ref:`existing-pointers-instantiation` for an example.
.. [#] https://docs.python.org/reference/datamodel.html#object.__new__
.. _finalization_method:
Finalization methods: :meth:`__dealloc__` and :meth:`__del__`
......
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