| in a file called :file:`setup.py`; then typing :: |
| |
| $ python setup.py build |
| |
| at a shell should produce a file :file:`noddy.so` in a subdirectory; move to |
| that directory and fire up Python --- you should be able to ``import noddy`` and |
| play around with Noddy objects. |
| |
n | .. % $ <-- bow to font-lock ;-( |
| |
| That wasn't so hard, was it? |
| |
| Of course, the current Noddy type is pretty uninteresting. It has no data and |
| doesn't do anything. It can't even be subclassed. |
| |
| |
| Adding data and methods to the Basic example |
| -------------------------------------------- |
| |
| Let's expend the basic example to add some data and methods. Let's also make |
| the type usable as a base class. We'll create a new module, :mod:`noddy2` that |
| adds these capabilities: |
| |
n | |
| .. include:: ../includes/noddy2.c |
| .. literalinclude:: ../includes/noddy2.c |
| :literal: |
| |
| |
| This version of the module has a number of changes. |
| |
| We've added an extra include:: |
| |
| #include "structmember.h" |
| |
| This include provides declarations that we use to handle attributes, as |
| * when we absolutely know that the reference count is greater than 1 |
| |
| * when we know that deallocation of the object [#]_ will not cause any calls |
| back into our type's code |
| |
| * when decrementing a reference count in a :attr:`tp_dealloc` handler when |
| garbage-collections is not supported [#]_ |
| |
n | * |
| |
| We want to want to expose our instance variables as attributes. There are a |
| We want to expose our instance variables as attributes. There are a |
| number of ways to do that. The simplest way is to define member definitions:: |
| |
| static PyMemberDef Noddy_members[] = { |
| {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, |
| "first name"}, |
| {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, |
| "last name"}, |
| {"number", T_INT, offsetof(Noddy, number), 0, |
| -------------------------------------------- |
| |
| In this section, we'll provide finer control over how the :attr:`first` and |
| :attr:`last` attributes are set in the :class:`Noddy` example. In the previous |
| version of our module, the instance variables :attr:`first` and :attr:`last` |
| could be set to non-string values or even deleted. We want to make sure that |
| these attributes always contain strings. |
| |
n | |
| .. include:: ../includes/noddy3.c |
| .. literalinclude:: ../includes/noddy3.c |
| :literal: |
| |
| |
| To provide greater control, over the :attr:`first` and :attr:`last` attributes, |
| we'll use custom getter and setter functions. Here are the functions for |
| getting and setting the :attr:`first` attribute:: |
| |
| Noddy_getfirst(Noddy *self, void *closure) |
| { |
| Py_INCREF(self->first); |
| object to be stored in the :attr:`first` or :attr:`last` attributes. [#]_ This |
| means that :class:`Noddy` objects can participate in cycles:: |
| |
| >>> import noddy2 |
| >>> n = noddy2.Noddy() |
| >>> l = [n] |
| >>> n.first = l |
| |
n | This is pretty silly, but it gives us an excuse to add support for the cyclic- |
n | This is pretty silly, but it gives us an excuse to add support for the |
| garbage collector to the :class:`Noddy` example. To support cyclic garbage |
| cyclic-garbage collector to the :class:`Noddy` example. To support cyclic |
| collection, types need to fill two slots and set a class flag that enables these |
| garbage collection, types need to fill two slots and set a class flag that |
| slots: |
| enables these slots: |
| |
n | |
| .. include:: ../includes/noddy4.c |
| .. literalinclude:: ../includes/noddy4.c |
| :literal: |
| |
| |
| The traversal method provides access to subobjects that could participate in |
| cycles:: |
| |
| static int |
| Noddy_traverse(Noddy *self, visitproc visit, void *arg) |
| { |
| int vret; |
| |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ |
| |
| That's pretty much it. If we had written custom :attr:`tp_alloc` or |
| :attr:`tp_free` slots, we'd need to modify them for cyclic-garbage collection. |
| Most extensions will use the versions automatically provided. |
| |
| |
n | Subclassing other types |
| ----------------------- |
| |
| It is possible to create new extension types that are derived from existing |
| types. It is easiest to inherit from the built in types, since an extension can |
| easily use the :class:`PyTypeObject` it needs. It can be difficult to share |
| these :class:`PyTypeObject` structures between extension modules. |
| |
| In this example we will create a :class:`Shoddy` type that inherits from the |
| builtin :class:`list` type. The new type will be completely compatible with |
| regular lists, but will have an additional :meth:`increment` method that |
| increases an internal counter. :: |
| |
| >>> import shoddy |
| >>> s = shoddy.Shoddy(range(3)) |
| >>> s.extend(s) |
| >>> print len(s) |
| 6 |
| >>> print s.increment() |
| 1 |
| >>> print s.increment() |
| 2 |
| |
| .. literalinclude:: ../includes/shoddy.c |
| |
| |
| As you can see, the source code closely resembles the :class:`Noddy` examples in |
| previous sections. We will break down the main differences between them. :: |
| |
| typedef struct { |
| PyListObject list; |
| int state; |
| } Shoddy; |
| |
| The primary difference for derived type objects is that the base type's object |
| structure must be the first value. The base type will already include the |
| :cfunc:`PyObject_HEAD` at the beginning of its structure. |
| |
| When a Python object is a :class:`Shoddy` instance, its *PyObject\** pointer can |
| be safely cast to both *PyListObject\** and *Shoddy\**. :: |
| |
| static int |
| Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) |
| { |
| if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) |
| return -1; |
| self->state = 0; |
| return 0; |
| } |
| |
| In the :attr:`__init__` method for our type, we can see how to call through to |
| the :attr:`__init__` method of the base type. |
| |
| This pattern is important when writing a type with custom :attr:`new` and |
| :attr:`dealloc` methods. The :attr:`new` method should not actually create the |
| memory for the object with :attr:`tp_alloc`, that will be handled by the base |
| class when calling its :attr:`tp_new`. |
| |
| When filling out the :cfunc:`PyTypeObject` for the :class:`Shoddy` type, you see |
| a slot for :cfunc:`tp_base`. Due to cross platform compiler issues, you can't |
| fill that field directly with the :cfunc:`PyList_Type`; it can be done later in |
| the module's :cfunc:`init` function. :: |
| |
| PyMODINIT_FUNC |
| initshoddy(void) |
| { |
| PyObject *m; |
| |
| ShoddyType.tp_base = &PyList_Type; |
| if (PyType_Ready(&ShoddyType) < 0) |
| return; |
| |
| m = Py_InitModule3("shoddy", NULL, "Shoddy module"); |
| if (m == NULL) |
| return; |
| |
| Py_INCREF(&ShoddyType); |
| PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); |
| } |
| |
| Before calling :cfunc:`PyType_Ready`, the type structure must have the |
| :attr:`tp_base` slot filled in. When we are deriving a new type, it is not |
| necessary to fill out the :attr:`tp_alloc` slot with :cfunc:`PyType_GenericNew` |
| -- the allocate function from the base type will be inherited. |
| |
| After that, calling :cfunc:`PyType_Ready` and adding the type object to the |
| module is the same as with the basic :class:`Noddy` examples. |
| |
| |
| .. _dnt-type-methods: |
| |
| Type Methods |
| ============ |
| |
| This section aims to give a quick fly-by on the various type methods you can |
| implement and what they do. |
| |
| Here is the definition of :ctype:`PyTypeObject`, with some fields only used in |
| debug builds omitted: |
| |
n | |
| .. include:: ../includes/typestruct.h |
| .. literalinclude:: ../includes/typestruct.h |
| :literal: |
| |
| |
| Now that's a *lot* of methods. Don't worry too much though - if you have a type |
| you want to define, the chances are very good that you will only implement a |
| handful of these. |
| |
| As you probably expect by now, we're going to go over this and give more |
| information about the various handlers. We won't go in the order they are |
| defined in the structure, because there is a lot of historical baggage that |
| |
| #. No special processing is needed to record that an attribute was looked up or |
| set, nor do actions need to be taken based on the value. |
| |
| Note that this list does not place any restrictions on the values of the |
| attributes, when the values are computed, or how relevant data is stored. |
| |
| When :cfunc:`PyType_Ready` is called, it uses three tables referenced by the |
n | type object to create *descriptors* which are placed in the dictionary of the |
n | type object to create :term:`descriptor`\s which are placed in the dictionary of the |
| type object. Each descriptor controls access to one attribute of the instance |
| object. Each of the tables is optional; if all three are *NULL*, instances of |
| the type will only have attributes that are inherited from their base type, and |
| should leave the :attr:`tp_getattro` and :attr:`tp_setattro` fields *NULL* as |
| well, allowing the base type to handle attributes. |
| |
| The tables are declared as three fields of the type object:: |
| |
| descriptors that are used at runtime is that any attribute defined this way can |
| have an associated doc string simply by providing the text in the table. An |
| application can use the introspection API to retrieve the descriptor from the |
| class object, and get the doc string using its :attr:`__doc__` attribute. |
| |
| As with the :attr:`tp_methods` table, a sentinel entry with a :attr:`name` value |
| of *NULL* is required. |
| |
n | .. % XXX Descriptors need to be explained in more detail somewhere, but |
n | .. XXX Descriptors need to be explained in more detail somewhere, but not here. |
| .. % not here. |
| |
| .. % |
| .. % Descriptor objects have two handler functions which correspond to |
| Descriptor objects have two handler functions which correspond to the |
| .. % the \member{tp_getattro} and \member{tp_setattro} handlers. The |
| \member{tp_getattro} and \member{tp_setattro} handlers. The |
| .. % \method{__get__()} handler is a function which is passed the |
| \method{__get__()} handler is a function which is passed the descriptor, |
| .. % descriptor, instance, and type objects, and returns the value of the |
| instance, and type objects, and returns the value of the attribute, or it |
| .. % attribute, or it returns \NULL{} and sets an exception. The |
| returns \NULL{} and sets an exception. The \method{__set__()} handler is |
| .. % \method{__set__()} handler is passed the descriptor, instance, type, |
| passed the descriptor, instance, type, and new value; |
| .. % and new value; |
| |
| |
| Type-specific Attribute Management |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| For simplicity, only the :ctype:`char\*` version will be demonstrated here; the |
| type of the name parameter is the only difference between the :ctype:`char\*` |
| and :ctype:`PyObject\*` flavors of the interface. This example effectively does |
| return result; |
| } |
| |
| |
| Abstract Protocol Support |
| ------------------------- |
| |
| Python supports a variety of *abstract* 'protocols;' the specific interfaces |
n | provided to use these interfaces are documented in the Python/C API Reference |
n | provided to use these interfaces are documented in :ref:`abstract`. |
| Manual (XXX reference: ../api/api.html) in the chapter "Abstract Objects Layer |
| |
| (XXX reference: ../api/abstract.html)." |
| |
| A number of these abstract interfaces were defined early in the development of |
| the Python implementation. In particular, the number, mapping, and sequence |
| protocols have been part of Python since the beginning. Other protocols have |
| been added over time. For protocols which depend on several handler routines |
| from the type implementation, the older protocols have been defined as optional |
| blocks of handlers referenced by the type object. For newer protocols there are |
| additional slots in the main type object, with a flag bit being set to indicate |
| type doesn't support garbage collection. Even if a type supports garbage |
| collection, there are calls that can be made to "untrack" the object from |
| garbage collection, however, these calls are advanced and not covered here. |
| |
| .. [#] We now know that the first and last members are strings, so perhaps we could be |
| less careful about decrementing their reference counts, however, we accept |
| instances of string subclasses. Even though deallocating normal strings won't |
| call back into our objects, we can't guarantee that deallocating an instance of |
t | a string subclass won't. call back into out objects. |
t | a string subclass won't call back into our objects. |
| |
| .. [#] Even in the third version, we aren't guaranteed to avoid cycles. Instances of |
| string subclasses are allowed and string subclasses could allow cycles even if |
| normal strings don't. |
| |