2. Definición de tipos de extensión: Tutorial
*********************************************

Python le permite al escritor de un módulo de extensión C definir
nuevos tipos que pueden ser manipulados desde el código Python, al
igual que los tipos incorporados "str" y "list". El código para todos
los tipos de extensión sigue un patrón, pero hay algunos detalles que
debe comprender antes de comenzar. Este documento es una introducción
suave al tema.


2.1. Lo Básico
==============

El tiempo de ejecución *CPython* ve todos los objetos de Python como
variables de tipo "PyObject*", que sirve como un "tipo base" para
todos los objetos de Python. La estructura "PyObject" solo contiene el
*reference count* del objeto y un puntero al "objeto tipo" del objeto.
Aquí es donde está la acción; el objeto tipo determina qué funciones
(C) llama el intérprete cuando, por ejemplo, se busca un atributo en
un objeto, se llama un método o se multiplica por otro objeto. Estas
funciones de C se denominan "métodos de tipo".

Por lo tanto, si desea definir un nuevo tipo de extensión, debe crear
un nuevo objeto de tipo.

Este tipo de cosas solo se pueden explicar con un ejemplo, por lo que
aquí hay un módulo mínimo, pero completo, que define un nuevo tipo
llamado "Custom" dentro de un módulo de extensión C "custom":

Nota:

  Lo que estamos mostrando aquí es la forma tradicional de definir
  tipos de extensión *estáticos*. Debe ser adecuado para la mayoría de
  los usos. La API de C también permite definir tipos de extensiones
  asignadas en el montón utilizando la función "PyType_FromSpec()",
  que no se trata en este tutorial.

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>

   typedef struct {
       PyObject_HEAD
       /* Type-specific fields go here. */
   } CustomObject;

   static PyTypeObject CustomType = {
       PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom.Custom",
       .tp_doc = "Custom objects",
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT,
       .tp_new = PyType_GenericNew,
   };

   static PyModuleDef custommodule = {
       PyModuleDef_HEAD_INIT,
       .m_name = "custom",
       .m_doc = "Example module that creates an extension type.",
       .m_size = -1,
   };

   PyMODINIT_FUNC
   PyInit_custom(void)
   {
       PyObject *m;
       if (PyType_Ready(&CustomType) < 0)
           return NULL;

       m = PyModule_Create(&custommodule);
       if (m == NULL)
           return NULL;

       Py_INCREF(&CustomType);
       if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) {
           Py_DECREF(&CustomType);
           Py_DECREF(m);
           return NULL;
       }

       return m;
   }

Ahora, eso es bastante para asimilar a la vez, pero espero que los
fragmentos le resulten familiares del capítulo anterior. Este archivo
define tres cosas:

1. Lo que contiene un **objeto** "Custom": esta es la estructura
   "CustomObject", que se asigna una vez para cada instancia de
   "Custom".

2. Cómo se comporta "Custom" **type**: esta es la estructura
   "CustomType", que define un conjunto de indicadores y punteros de
   función que el intérprete inspecciona cuando se solicitan
   operaciones específicas.

3. Cómo inicializar el módulo "custom": esta es la función
   "PyInit_custom" y la estructura asociada "custommodule".

La primera parte es:

   typedef struct {
       PyObject_HEAD
   } CustomObject;

Esto es lo que contendrá un objeto personalizado. "PyObject_HEAD" es
obligatorio al comienzo de cada estructura de objeto y define un campo
llamado "ob_base" de tipo "PyObject", que contiene un puntero a un
objeto de tipo y un recuento de referencia (estos pueden ser accedidos
mediante las macros "Py_REFCNT" y "Py_TYPE" respectivamente). El
motivo de la macro es abstraer el diseño y habilitar campos
adicionales en las compilaciones de depuración.

Nota:

  No hay punto y coma (;) arriba después de la macro "PyObject_HEAD".
  Tenga cuidado de agregar uno por accidente: algunos compiladores se
  quejarán.

Por supuesto, los objetos generalmente almacenan datos adicionales
además del estándar "PyObject_HEAD" repetitivo; por ejemplo, aquí está
la definición de puntos flotantes del estándar de Python:

   typedef struct {
       PyObject_HEAD
       double ob_fval;
   } PyFloatObject;

La segunda parte es la definición del tipo de objecto.

   static PyTypeObject CustomType = {
       PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom.Custom",
       .tp_doc = "Custom objects",
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT,
       .tp_new = PyType_GenericNew,
   };

Nota:

  Recomendamos utilizar los inicializadores designados al estilo C99
  como se indica arriba, para evitar enumerar todos los campos
  "PyTypeObject" que no le interesan y también para evitar preocuparse
  por el orden de declaración de los campos.

La definición real de "PyTypeObject" en "object.h" tiene muchos más
campos que la definición anterior. El compilador de C rellenará los
campos restantes con ceros, y es una práctica común no especificarlos
explícitamente a menos que los necesite.

Lo vamos a separar, un campo a la vez:

   PyVarObject_HEAD_INIT(NULL, 0)

Esta línea es obligatoria para inicializar el campo "ob_base"
mencionado anteriormente.

   .tp_name = "custom.Custom",

El nombre de nuestro tipo. Esto aparecerá en la representación textual
predeterminada de nuestros objetos y en algunos mensajes de error, por
ejemplo:

   >>> "" + custom.Custom()
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: can only concatenate str (not "custom.Custom") to str

Tenga en cuenta que el nombre es un nombre punteado que incluye tanto
el nombre del módulo como el nombre del tipo dentro del módulo. El
módulo en este caso es "custom" y el tipo es "Custom", por lo que
establecemos el nombre del tipo en "custom.Custom". Usar la ruta de
importación punteada real es importante para que su tipo sea
compatible con los módulos "pydoc" y "pickle".

   .tp_basicsize = sizeof(CustomObject),
   .tp_itemsize = 0,

Esto es para que Python sepa cuánta memoria asignar al crear
instancias nuevas "Custom". "tp_itemsize" solo se usa para objetos de
tamaño variable y, de lo contrario, debería ser cero.

Nota:

  Si desea que su tipo pueda tener subclases desde Python, y su tipo
  tiene el mismo "tp_basicsize" como su tipo base, puede tener
  problemas con la herencia múltiple. Una subclase de Python de su
  tipo tendrá que enumerar su tipo primero en su "__bases__", o de lo
  contrario no podrá llamar al método de su tipo "__new__()" sin
  obtener un error. Puede evitar este problema asegurándose de que su
  tipo tenga un valor mayor para "tp_basicsize" que su tipo base. La
  mayoría de las veces, esto será cierto de todos modos, porque su
  tipo base será "object", o de lo contrario agregará miembros de
  datos a su tipo base y, por lo tanto, aumentará su tamaño.

Configuramos las banderas de clase a "Py_TPFLAGS_DEFAULT".

   .tp_flags = Py_TPFLAGS_DEFAULT,

Todos los tipos deben incluir esta constante en sus banderas. Habilita
todos los miembros definidos hasta al menos Python 3.3. Si necesita
más miembros, necesitará O (*OR*) las banderas correspondientes.

Proporcionamos una cadena de documentos para el tipo en "tp_doc".

   .tp_doc = "Custom objects",

Para habilitar la creación de objetos, debemos proporcionar un
controlador "tp_new". Este es el equivalente del método Python
"__new__()", pero debe especificarse explícitamente. En este caso,
podemos usar la implementación predeterminada proporcionada por la
función API "PyType_GenericNew()".

   .tp_new = PyType_GenericNew,

Todo lo demás en el archivo debe ser familiar, excepto algún código en
"PyInit_custom()":

   if (PyType_Ready(&CustomType) < 0)
       return;

Esto inicializa el tipo "Custom", completando un número de miembros
con los valores predeterminados apropiados, que incluyen "ob_type" que
inicialmente configuramos en "NULL".

   Py_INCREF(&CustomType);
   if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) {
       Py_DECREF(&CustomType);
       Py_DECREF(m);
       return NULL;
   }

Esto agrega el tipo al diccionario del módulo. Esto nos permite crear
instancias "Custom" llamando la clase "Custom":

   >>> import custom
   >>> mycustom = custom.Custom()

¡Eso es! Todo lo que queda es construirlo; ponga el código anterior en
un archivo llamado "custom.c" y:

   from distutils.core import setup, Extension
   setup(name="custom", version="1.0",
         ext_modules=[Extension("custom", ["custom.c"])])

en un archivo llamado "setup.py"; luego escribiendo

   $ python setup.py build

en un shell debería producir un archivo "custom.so" en un
subdirectorio; muévete a ese directorio y abre Python --- deberías
poder "import custom" y jugar con objetos personalizados.

Eso no fue tan difícil, ¿verdad?

Por supuesto, el tipo personalizado actual es bastante poco
interesante. No tiene datos y no hace nada. Ni siquiera se puede
subclasificar.

Nota:

  Si bien esta documentación muestra el módulo estándar "distutils"
  para construir extensiones C, se recomienda en casos de uso del
  mundo real utilizar la biblioteca "setuptools" más nueva y mejor
  mantenida. La documentación sobre cómo hacer esto está fuera del
  alcance de este documento y se puede encontrar en la Guía de usuario
  del Empaquetamiento de Python.


2.2. Agregar datos y métodos al ejemplo básico
==============================================

Extendamos el ejemplo básico para agregar algunos datos y métodos.
También hagamos que el tipo sea utilizable como una clase base.
Crearemos un nuevo módulo, "custom2" que agrega estas capacidades:

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include "structmember.h"

   typedef struct {
       PyObject_HEAD
       PyObject *first; /* first name */
       PyObject *last;  /* last name */
       int number;
   } CustomObject;

   static void
   Custom_dealloc(CustomObject *self)
   {
       Py_XDECREF(self->first);
       Py_XDECREF(self->last);
       Py_TYPE(self)->tp_free((PyObject *) self);
   }

   static PyObject *
   Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       CustomObject *self;
       self = (CustomObject *) type->tp_alloc(type, 0);
       if (self != NULL) {
           self->first = PyUnicode_FromString("");
           if (self->first == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->last = PyUnicode_FromString("");
           if (self->last == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->number = 0;
       }
       return (PyObject *) self;
   }

   static int
   Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
   {
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL, *tmp;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           tmp = self->first;
           Py_INCREF(first);
           self->first = first;
           Py_XDECREF(tmp);
       }
       if (last) {
           tmp = self->last;
           Py_INCREF(last);
           self->last = last;
           Py_XDECREF(tmp);
       }
       return 0;
   }

   static PyMemberDef Custom_members[] = {
       {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0,
        "first name"},
       {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0,
        "last name"},
       {"number", T_INT, offsetof(CustomObject, number), 0,
        "custom number"},
       {NULL}  /* Sentinel */
   };

   static PyObject *
   Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
   {
       if (self->first == NULL) {
           PyErr_SetString(PyExc_AttributeError, "first");
           return NULL;
       }
       if (self->last == NULL) {
           PyErr_SetString(PyExc_AttributeError, "last");
           return NULL;
       }
       return PyUnicode_FromFormat("%S %S", self->first, self->last);
   }

   static PyMethodDef Custom_methods[] = {
       {"name", (PyCFunction) Custom_name, METH_NOARGS,
        "Return the name, combining the first and last name"
       },
       {NULL}  /* Sentinel */
   };

   static PyTypeObject CustomType = {
       PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom2.Custom",
       .tp_doc = "Custom objects",
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
       .tp_new = Custom_new,
       .tp_init = (initproc) Custom_init,
       .tp_dealloc = (destructor) Custom_dealloc,
       .tp_members = Custom_members,
       .tp_methods = Custom_methods,
   };

   static PyModuleDef custommodule = {
       PyModuleDef_HEAD_INIT,
       .m_name = "custom2",
       .m_doc = "Example module that creates an extension type.",
       .m_size = -1,
   };

   PyMODINIT_FUNC
   PyInit_custom2(void)
   {
       PyObject *m;
       if (PyType_Ready(&CustomType) < 0)
           return NULL;

       m = PyModule_Create(&custommodule);
       if (m == NULL)
           return NULL;

       Py_INCREF(&CustomType);
       if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) {
           Py_DECREF(&CustomType);
           Py_DECREF(m);
           return NULL;
       }

       return m;
   }

Esta versión del módulo tiene una serie de cambios.

Hemos agregado una inclusión adicional:

   #include <structmember.h>

Esto incluye declaraciones que usamos para manejar atributos, como se
describe un poco más adelante.

El tipo "Custom" ahora tiene tres atributos de datos en su estructura
C, *first*, *last* y *number*. Las variables *first* y *last* son
cadenas de caracteres de Python que contienen nombres y apellidos. El
atributo *number* es un entero C.

La estructura del objeto se actualiza en consecuencia:

   typedef struct {
       PyObject_HEAD
       PyObject *first; /* first name */
       PyObject *last;  /* last name */
       int number;
   } CustomObject;

Debido a que ahora tenemos datos para administrar, debemos ser más
cuidadosos con la asignación de objetos y la desasignación. Como
mínimo, necesitamos un método de desasignación:

   static void
   Custom_dealloc(CustomObject *self)
   {
       Py_XDECREF(self->first);
       Py_XDECREF(self->last);
       Py_TYPE(self)->tp_free((PyObject *) self);
   }

que se asigna al miembro "tp_dealloc":

   .tp_dealloc = (destructor) Custom_dealloc,

Este método primero borra los recuentos de referencia de los dos
atributos de Python. "Py_XDECREF()" maneja correctamente el caso donde
su argumento es "NULL" (lo que podría ocurrir aquí si "tp_new" fallara
a mitad de camino). Luego llama al miembro "tp_free" del tipo de
objeto (calculado por "Py_TYPE(self)") para liberar la memoria del
objeto. Tenga en cuenta que el tipo de objeto podría no ser
"CustomType", porque el objeto puede ser una instancia de una
subclase.

Nota:

  La conversión explícita a "destructor" anterior es necesaria porque
  definimos "Custom_dealloc" para tomar un argumento "CustomObject *",
  pero el puntero de función "tp_dealloc" espera recibir un argumento
  "PyObject *". De lo contrario, el compilador emitirá una
  advertencia. Este es un polimorfismo orientado a objetos, en C!

Queremos asegurarnos de que el nombre y el apellido se inicialicen en
cadenas de caracteres vacías, por lo que proporcionamos una
implementación "tp_new":

   static PyObject *
   Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       CustomObject *self;
       self = (CustomObject *) type->tp_alloc(type, 0);
       if (self != NULL) {
           self->first = PyUnicode_FromString("");
           if (self->first == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->last = PyUnicode_FromString("");
           if (self->last == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->number = 0;
       }
       return (PyObject *) self;
   }

e instalarlo en el miembro "tp_new":

   .tp_new = Custom_new,

El controlador "tp_new" es responsable de crear (en lugar de
inicializar) objetos del tipo. Está expuesto en Python como el método
"__new__()". No es necesario definir un miembro "tp_new", y de hecho
muchos tipos de extensiones simplemente reutilizarán
"PyType_GenericNew()" como se hizo en la primera versión del tipo
"Personalizado" anterior. En este caso, usamos el controlador "tp_new"
para inicializar los atributos "first" y "last" a valores
predeterminados que no sean "NULL".

"tp_new" se pasa el tipo que se instancia (no necesariamente
"CustomType", si se instancia una subclase) y cualquier argumento
pasado cuando se llamó al tipo, y se espera que retorna la instancia
creada. Los manejadores "tp_new" siempre aceptan argumentos
posicionales y de palabras clave, pero a menudo ignoran los
argumentos, dejando el manejo de argumentos al inicializador (también
conocido como, "tp_init" en C o "__init__" en Python).

Nota:

  "tp_new" no debería llamar explícitamente a "tp_init", ya que el
  intérprete lo hará por sí mismo.

La implementación "tp_new" llama al "tp_alloc" para asignar memoria:

   self = (CustomObject *) type->tp_alloc(type, 0);

Como la asignación de memoria puede fallar, debemos verificar el
resultado "tp_alloc" contra "NULL" antes de continuar.

Nota:

  No llenamos la ranura "tp_alloc" nosotros mismos. Más bien
  "PyType_Ready()" lo llena para nosotros al heredarlo de nuestra
  clase base, que es "object" por defecto. La mayoría de los tipos
  utilizan la estrategia de asignación predeterminada.

Nota:

  Si está creando una cooperativa "tp_new" (una que llama a un tipo
  base "tp_new" o "__new__()"), *no* debe intentar determinar a qué
  método llamar utilizando el orden de resolución del método en tiempo
  de ejecución. Siempre determine estáticamente a qué tipo va a
  llamar, y llame a su "tp_new" directamente, o mediante
  "type->tp_base->tp_new". Si no hace esto, las subclases de Python de
  su tipo que también heredan de otras clases definidas por Python
  pueden no funcionar correctamente. (Específicamente, es posible que
  no pueda crear instancias de tales subclases sin obtener un
  "TypeError").

También definimos una función de inicialización que acepta argumentos
para proporcionar valores iniciales para nuestra instancia:

   static int
   Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
   {
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL, *tmp;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           tmp = self->first;
           Py_INCREF(first);
           self->first = first;
           Py_XDECREF(tmp);
       }
       if (last) {
           tmp = self->last;
           Py_INCREF(last);
           self->last = last;
           Py_XDECREF(tmp);
       }
       return 0;
   }

rellenando la ranura "tp_init".

   .tp_init = (initproc) Custom_init,

La ranura "tp_init" está expuesta en Python como el método
"__init__()". Se utiliza para inicializar un objeto una vez creado.
Los inicializadores siempre aceptan argumentos posicionales y de
palabras clave, y deben retornar "0" en caso de éxito o "-1" en caso
de error.

A diferencia del controlador "tp_new", no hay garantía de que se llame
a "tp_init" (por ejemplo, el módulo "pickle" por defecto no llama a
"__init__()" en instancias no controladas ) También se puede llamar
varias veces. Cualquiera puede llamar al método "__init__()" en
nuestros objetos. Por esta razón, debemos tener mucho cuidado al
asignar los nuevos valores de atributo. Podríamos sentirnos tentados,
por ejemplo, a asignar el "primer" miembro de esta manera:

   if (first) {
       Py_XDECREF(self->first);
       Py_INCREF(first);
       self->first = first;
   }

But this would be risky.  Our type doesn't restrict the type of the
"first" member, so it could be any kind of object.  It could have a
destructor that causes code to be executed that tries to access the
"first" member; or that destructor could release the *Global
interpreter Lock* and let arbitrary code run in other threads that
accesses and modifies our object.

Para ser paranoicos y protegernos de esta posibilidad, casi siempre
reasignamos miembros antes de disminuir sus recuentos de referencias.
¿Cuándo no tenemos que hacer esto?

* cuando sabemos absolutamente que el recuento de referencia es mayor
  que 1;

* cuando sabemos que la desasignación del objeto [1] no liberará el
  *GIL* ni causará ninguna llamada al código de nuestro tipo;

* al disminuir un recuento de referencias en un manejador "tp_dealloc"
  en un tipo que no admite la recolección de basura cíclica [2].

Queremos exponer nuestras variables de instancia como atributos. Hay
varias formas de hacerlo. La forma más simple es definir definiciones
de miembros:

   static PyMemberDef Custom_members[] = {
       {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0,
        "first name"},
       {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0,
        "last name"},
       {"number", T_INT, offsetof(CustomObject, number), 0,
        "custom number"},
       {NULL}  /* Sentinel */
   };

y poner las definiciones en la ranura "tp_members":

   .tp_members = Custom_members,

Cada definición de miembro tiene un nombre de miembro, tipo,
desplazamiento, banderas de acceso y cadena de caracteres de
documentación. Consulte la sección Gestión de atributos genéricos a
continuación para obtener más detalles.

Una desventaja de este enfoque es que no proporciona una forma de
restringir los tipos de objetos que se pueden asignar a los atributos
de Python. Esperamos que el nombre y el apellido sean cadenas, pero se
pueden asignar objetos de Python. Además, los atributos se pueden
eliminar, configurando los punteros C en "NULL". Si bien podemos
asegurarnos de que los miembros se inicialicen en valores que no sean
"NULL", los miembros se pueden establecer en "NULL" si se eliminan los
atributos.

Definimos un método único, "Custom.name()", que genera el nombre de
los objetos como la concatenación de los nombres y apellidos.

   static PyObject *
   Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
   {
       if (self->first == NULL) {
           PyErr_SetString(PyExc_AttributeError, "first");
           return NULL;
       }
       if (self->last == NULL) {
           PyErr_SetString(PyExc_AttributeError, "last");
           return NULL;
       }
       return PyUnicode_FromFormat("%S %S", self->first, self->last);
   }

El método se implementa como una función C que toma una instancia de
"Custom" (o subclase "Custom") como primer argumento. Los métodos
siempre toman una instancia como primer argumento. Los métodos a
menudo también toman argumentos posicionales y de palabras clave, pero
en este caso no tomamos ninguno y no necesitamos aceptar una tupla de
argumentos posicionales o un diccionario de argumentos de palabras
clave. Este método es equivalente al método Python:

   def name(self):
       return "%s %s" % (self.first, self.last)

Tenga en cuenta que tenemos que verificar la posibilidad de que
nuestros miembros "first" y "last" sean "NULL". Esto se debe a que se
pueden eliminar, en cuyo caso se establecen en "NULL". Sería mejor
evitar la eliminación de estos atributos y restringir los valores de
los atributos para que sean cadenas de caracteres. Veremos cómo
hacerlo en la siguiente sección.

Ahora que hemos definido el método, necesitamos crear un arreglo de
definiciones de métodos:

   static PyMethodDef Custom_methods[] = {
       {"name", (PyCFunction) Custom_name, METH_NOARGS,
        "Return the name, combining the first and last name"
       },
       {NULL}  /* Sentinel */
   };

(tenga en cuenta que usamos el indicador "METH_NOARGS" para indicar
que el método no espera argumentos distintos de *self*)

y asignarlo a la ranura "tp_methods":

   .tp_methods = Custom_methods,

Finalmente, haremos que nuestro tipo sea utilizable como una clase
base para la subclase. Hemos escrito nuestros métodos cuidadosamente
hasta ahora para que no hagan suposiciones sobre el tipo de objeto que
se está creando o utilizando, por lo que todo lo que tenemos que hacer
es agregar "Py_TPFLAGS_BASETYPE" a nuestra definición de bandera de
clase:

   .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,

Cambiamos el nombre de "PyInit_custom()" a "PyInit_custom2()",
actualizamos el nombre del módulo en la estructura "PyModuleDef" y
actualizamos el nombre completo de la clase en la estructura
"PyTypeObject".

Finalmente, actualizamos nuestro archivo "setup.py" para construir el
nuevo módulo:

   from distutils.core import setup, Extension
   setup(name="custom", version="1.0",
         ext_modules=[
            Extension("custom", ["custom.c"]),
            Extension("custom2", ["custom2.c"]),
            ])


2.3. Proporcionar un control más preciso sobre los atributos de datos
=====================================================================

En esta sección, proporcionaremos un control más preciso sobre cómo se
establecen los atributos "first" y "last" en el ejemplo "Custom". En
la versión anterior de nuestro módulo, las variables de instancia
"first" y "last" podrían establecerse en valores que no sean de cadena
o incluso eliminarse. Queremos asegurarnos de que estos atributos
siempre contengan cadenas.

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include "structmember.h"

   typedef struct {
       PyObject_HEAD
       PyObject *first; /* first name */
       PyObject *last;  /* last name */
       int number;
   } CustomObject;

   static void
   Custom_dealloc(CustomObject *self)
   {
       Py_XDECREF(self->first);
       Py_XDECREF(self->last);
       Py_TYPE(self)->tp_free((PyObject *) self);
   }

   static PyObject *
   Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       CustomObject *self;
       self = (CustomObject *) type->tp_alloc(type, 0);
       if (self != NULL) {
           self->first = PyUnicode_FromString("");
           if (self->first == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->last = PyUnicode_FromString("");
           if (self->last == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->number = 0;
       }
       return (PyObject *) self;
   }

   static int
   Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
   {
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL, *tmp;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           tmp = self->first;
           Py_INCREF(first);
           self->first = first;
           Py_DECREF(tmp);
       }
       if (last) {
           tmp = self->last;
           Py_INCREF(last);
           self->last = last;
           Py_DECREF(tmp);
       }
       return 0;
   }

   static PyMemberDef Custom_members[] = {
       {"number", T_INT, offsetof(CustomObject, number), 0,
        "custom number"},
       {NULL}  /* Sentinel */
   };

   static PyObject *
   Custom_getfirst(CustomObject *self, void *closure)
   {
       Py_INCREF(self->first);
       return self->first;
   }

   static int
   Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
   {
       PyObject *tmp;
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The first attribute value must be a string");
           return -1;
       }
       tmp = self->first;
       Py_INCREF(value);
       self->first = value;
       Py_DECREF(tmp);
       return 0;
   }

   static PyObject *
   Custom_getlast(CustomObject *self, void *closure)
   {
       Py_INCREF(self->last);
       return self->last;
   }

   static int
   Custom_setlast(CustomObject *self, PyObject *value, void *closure)
   {
       PyObject *tmp;
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The last attribute value must be a string");
           return -1;
       }
       tmp = self->last;
       Py_INCREF(value);
       self->last = value;
       Py_DECREF(tmp);
       return 0;
   }

   static PyGetSetDef Custom_getsetters[] = {
       {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
        "first name", NULL},
       {"last", (getter) Custom_getlast, (setter) Custom_setlast,
        "last name", NULL},
       {NULL}  /* Sentinel */
   };

   static PyObject *
   Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
   {
       return PyUnicode_FromFormat("%S %S", self->first, self->last);
   }

   static PyMethodDef Custom_methods[] = {
       {"name", (PyCFunction) Custom_name, METH_NOARGS,
        "Return the name, combining the first and last name"
       },
       {NULL}  /* Sentinel */
   };

   static PyTypeObject CustomType = {
       PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom3.Custom",
       .tp_doc = "Custom objects",
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
       .tp_new = Custom_new,
       .tp_init = (initproc) Custom_init,
       .tp_dealloc = (destructor) Custom_dealloc,
       .tp_members = Custom_members,
       .tp_methods = Custom_methods,
       .tp_getset = Custom_getsetters,
   };

   static PyModuleDef custommodule = {
       PyModuleDef_HEAD_INIT,
       .m_name = "custom3",
       .m_doc = "Example module that creates an extension type.",
       .m_size = -1,
   };

   PyMODINIT_FUNC
   PyInit_custom3(void)
   {
       PyObject *m;
       if (PyType_Ready(&CustomType) < 0)
           return NULL;

       m = PyModule_Create(&custommodule);
       if (m == NULL)
           return NULL;

       Py_INCREF(&CustomType);
       if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) {
           Py_DECREF(&CustomType);
           Py_DECREF(m);
           return NULL;
       }

       return m;
   }

Para proporcionar un mayor control sobre los atributos "first" y
"last", usaremos funciones personalizadas *getter* y *setter*. Estas
son las funciones para obtener y configurar el atributo "first":

   static PyObject *
   Custom_getfirst(CustomObject *self, void *closure)
   {
       Py_INCREF(self->first);
       return self->first;
   }

   static int
   Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
   {
       PyObject *tmp;
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The first attribute value must be a string");
           return -1;
       }
       tmp = self->first;
       Py_INCREF(value);
       self->first = value;
       Py_DECREF(tmp);
       return 0;
   }

La función *getter* se pasa al objeto "Custom" y un "cierre"
(*closure*), que es un puntero nulo. En este caso, se ignora el
cierre. (El cierre admite un uso avanzado en el que los datos de
definición se pasan al captador y al definidor. Esto podría, por
ejemplo, usarse para permitir un solo conjunto de funciones de
captador y definidor que deciden que el atributo se obtenga o
establezca en función de los datos en el cierre.)

La función *setter* pasa el objeto "Custom", el nuevo valor y el
cierre. El nuevo valor puede ser "NULL", en cuyo caso se está
eliminando el atributo. En nuestro *setter*, generamos un error si el
atributo se elimina o si su nuevo valor no es una cadena.

Creamos un arreglo de estructuras "PyGetSetDef":

   static PyGetSetDef Custom_getsetters[] = {
       {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
        "first name", NULL},
       {"last", (getter) Custom_getlast, (setter) Custom_setlast,
        "last name", NULL},
       {NULL}  /* Sentinel */
   };

y lo registra en la ranura "tp_getset":

   .tp_getset = Custom_getsetters,

El último elemento en la estructura "PyGetSetDef" es el "cierre"
(*closure*) mencionado anteriormente. En este caso, no estamos usando
un cierre, por lo que simplemente pasamos "NULL".

También eliminamos las definiciones de miembro para estos atributos:

   static PyMemberDef Custom_members[] = {
       {"number", T_INT, offsetof(CustomObject, number), 0,
        "custom number"},
       {NULL}  /* Sentinel */
   };

También necesitamos actualizar el manejador "tp_init" para permitir
que solo se pasen las cadenas [3]:

   static int
   Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
   {
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL, *tmp;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           tmp = self->first;
           Py_INCREF(first);
           self->first = first;
           Py_DECREF(tmp);
       }
       if (last) {
           tmp = self->last;
           Py_INCREF(last);
           self->last = last;
           Py_DECREF(tmp);
       }
       return 0;
   }

Con estos cambios, podemos asegurar que los miembros "primero" y
"último" nunca sean "NULL", por lo que podemos eliminar las
comprobaciones de los valores "NULL" en casi todos los casos. Esto
significa que la mayoría de las llamadas "Py_XDECREF()" se pueden
convertir en llamadas "Py_DECREF()". El único lugar donde no podemos
cambiar estas llamadas es en la implementación "tp_dealloc", donde
existe la posibilidad de que la inicialización de estos miembros falle
en "tp_new".

También cambiamos el nombre de la función de inicialización del módulo
y el nombre del módulo en la función de inicialización, como lo
hicimos antes, y agregamos una definición adicional al archivo
"setup.py".


2.4. Apoyo a la recolección de basura cíclica
=============================================

Python tiene un *recolector de basura cíclico (GC)* que puede
identificar objetos innecesarios incluso cuando sus recuentos de
referencia no son cero. Esto puede suceder cuando los objetos están
involucrados en ciclos. Por ejemplo, considere:

   >>> l = []
   >>> l.append(l)
   >>> del l

En este ejemplo, creamos una lista que se contiene a sí misma. Cuando
lo eliminamos, todavía tiene una referencia de sí mismo. Su recuento
de referencia no cae a cero. Afortunadamente, el recolector cíclico de
basura de Python finalmente descubrirá que la lista es basura y la
liberará.

En la segunda versión del ejemplo "Custom", permitimos que cualquier
tipo de objeto se almacene en "first" o "last" atributos [4]. Además,
en la segunda y tercera versión, permitimos subclases "Custom", y las
subclases pueden agregar atributos arbitrarios. Por cualquiera de esos
dos motivos, los objetos "Custom" pueden participar en ciclos:

   >>> import custom3
   >>> class Derived(custom3.Custom): pass
   ...
   >>> n = Derived()
   >>> n.some_attribute = n

Para permitir que una instancia de "Custom" que participa en un ciclo
de referencia sea detectada y recolectada correctamente por el GC
cíclico, nuestro tipo "Custom" necesita llenar dos espacios
adicionales y habilitar un indicador que permita estos espacios:

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include "structmember.h"

   typedef struct {
       PyObject_HEAD
       PyObject *first; /* first name */
       PyObject *last;  /* last name */
       int number;
   } CustomObject;

   static int
   Custom_traverse(CustomObject *self, visitproc visit, void *arg)
   {
       Py_VISIT(self->first);
       Py_VISIT(self->last);
       return 0;
   }

   static int
   Custom_clear(CustomObject *self)
   {
       Py_CLEAR(self->first);
       Py_CLEAR(self->last);
       return 0;
   }

   static void
   Custom_dealloc(CustomObject *self)
   {
       PyObject_GC_UnTrack(self);
       Custom_clear(self);
       Py_TYPE(self)->tp_free((PyObject *) self);
   }

   static PyObject *
   Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       CustomObject *self;
       self = (CustomObject *) type->tp_alloc(type, 0);
       if (self != NULL) {
           self->first = PyUnicode_FromString("");
           if (self->first == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->last = PyUnicode_FromString("");
           if (self->last == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->number = 0;
       }
       return (PyObject *) self;
   }

   static int
   Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
   {
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL, *tmp;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           tmp = self->first;
           Py_INCREF(first);
           self->first = first;
           Py_DECREF(tmp);
       }
       if (last) {
           tmp = self->last;
           Py_INCREF(last);
           self->last = last;
           Py_DECREF(tmp);
       }
       return 0;
   }

   static PyMemberDef Custom_members[] = {
       {"number", T_INT, offsetof(CustomObject, number), 0,
        "custom number"},
       {NULL}  /* Sentinel */
   };

   static PyObject *
   Custom_getfirst(CustomObject *self, void *closure)
   {
       Py_INCREF(self->first);
       return self->first;
   }

   static int
   Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
   {
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The first attribute value must be a string");
           return -1;
       }
       Py_INCREF(value);
       Py_CLEAR(self->first);
       self->first = value;
       return 0;
   }

   static PyObject *
   Custom_getlast(CustomObject *self, void *closure)
   {
       Py_INCREF(self->last);
       return self->last;
   }

   static int
   Custom_setlast(CustomObject *self, PyObject *value, void *closure)
   {
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The last attribute value must be a string");
           return -1;
       }
       Py_INCREF(value);
       Py_CLEAR(self->last);
       self->last = value;
       return 0;
   }

   static PyGetSetDef Custom_getsetters[] = {
       {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
        "first name", NULL},
       {"last", (getter) Custom_getlast, (setter) Custom_setlast,
        "last name", NULL},
       {NULL}  /* Sentinel */
   };

   static PyObject *
   Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
   {
       return PyUnicode_FromFormat("%S %S", self->first, self->last);
   }

   static PyMethodDef Custom_methods[] = {
       {"name", (PyCFunction) Custom_name, METH_NOARGS,
        "Return the name, combining the first and last name"
       },
       {NULL}  /* Sentinel */
   };

   static PyTypeObject CustomType = {
       PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom4.Custom",
       .tp_doc = "Custom objects",
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
       .tp_new = Custom_new,
       .tp_init = (initproc) Custom_init,
       .tp_dealloc = (destructor) Custom_dealloc,
       .tp_traverse = (traverseproc) Custom_traverse,
       .tp_clear = (inquiry) Custom_clear,
       .tp_members = Custom_members,
       .tp_methods = Custom_methods,
       .tp_getset = Custom_getsetters,
   };

   static PyModuleDef custommodule = {
       PyModuleDef_HEAD_INIT,
       .m_name = "custom4",
       .m_doc = "Example module that creates an extension type.",
       .m_size = -1,
   };

   PyMODINIT_FUNC
   PyInit_custom4(void)
   {
       PyObject *m;
       if (PyType_Ready(&CustomType) < 0)
           return NULL;

       m = PyModule_Create(&custommodule);
       if (m == NULL)
           return NULL;

       Py_INCREF(&CustomType);
       if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) {
           Py_DECREF(&CustomType);
           Py_DECREF(m);
           return NULL;
       }

       return m;
   }

Primero, el método transversal permite que el GC cíclico conozca los
subobjetos que podrían participar en los ciclos:

   static int
   Custom_traverse(CustomObject *self, visitproc visit, void *arg)
   {
       int vret;
       if (self->first) {
           vret = visit(self->first, arg);
           if (vret != 0)
               return vret;
       }
       if (self->last) {
           vret = visit(self->last, arg);
           if (vret != 0)
               return vret;
       }
       return 0;
   }

Para cada subobjeto que puede participar en ciclos, necesitamos llamar
a la función "visit()", que se pasa al método transversal. La función
"visit()" toma como argumentos el subobjeto y el argumento extra *arg*
pasados al método transversal. Retorna un valor entero que debe
retornarse si no es cero.

Python proporciona una macro "Py_VISIT()" que automatiza las funciones
de visita de llamada. Con "Py_VISIT()", podemos minimizar la cantidad
de repeticiones en "Custom_traverse":

   static int
   Custom_traverse(CustomObject *self, visitproc visit, void *arg)
   {
       Py_VISIT(self->first);
       Py_VISIT(self->last);
       return 0;
   }

Nota:

  La implementación "tp_traverse" debe nombrar sus argumentos
  exactamente *visit* y *arg* para usar "Py_VISIT()".

En segundo lugar, debemos proporcionar un método para borrar cualquier
subobjeto que pueda participar en los ciclos:

   static int
   Custom_clear(CustomObject *self)
   {
       Py_CLEAR(self->first);
       Py_CLEAR(self->last);
       return 0;
   }

Observe el uso de la macro "Py_CLEAR()". Es la forma recomendada y
segura de borrar los atributos de datos de tipos arbitrarios al tiempo
que disminuye sus recuentos de referencia. Si tuviera que llamar a
"Py_XDECREF()" en lugar del atributo antes de establecerlo en "NULL",
existe la posibilidad de que el destructor del atributo vuelva a
llamar al código que lee el atributo nuevamente (*especialmente* si
hay un ciclo de referencia).

Nota:

  Puede emular "Py_CLEAR()" escribiendo:

     PyObject *tmp;
     tmp = self->first;
     self->first = NULL;
     Py_XDECREF(tmp);

  Sin embargo, es mucho más fácil y menos propenso a errores usar
  siempre "Py_CLEAR()" al eliminar un atributo. ¡No intentes micro-
  optimizar a expensas de la robustez!

El desasignador "Custom_dealloc" puede llamar a un código arbitrario
al borrar los atributos. Significa que el GC circular se puede activar
dentro de la función. Dado que el GC asume que el recuento de
referencias no es cero, debemos destrabar el objeto del GC llamando a
"PyObject_GC_UnTrack()" antes de borrar los miembros. Aquí está
nuestro reubicador reimplementado usando "PyObject_GC_UnTrack()" y
"Custom_clear":

   static void
   Custom_dealloc(CustomObject *self)
   {
       PyObject_GC_UnTrack(self);
       Custom_clear(self);
       Py_TYPE(self)->tp_free((PyObject *) self);
   }

Finalmente, agregamos el indicador "Py_TPFLAGS_HAVE_GC" a los
indicadores de clase:

   .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,

Eso es prácticamente todo. Si hubiéramos escrito controladores
personalizados "tp_alloc" o "tp_free", tendríamos que modificarlos
para la recolección de basura cíclica. La mayoría de las extensiones
usarán las versiones proporcionadas automáticamente.


2.5. Subclases de otros tipos
=============================

Es posible crear nuevos tipos de extensión que se derivan de los tipos
existentes. Es más fácil heredar de los tipos incorporados, ya que una
extensión puede usar fácilmente "PyTypeObject" que necesita. Puede ser
difícil compartir estas estructuras "PyTypeObject" entre módulos de
extensión.

En este ejemplo crearemos un tipo "SubList" que hereda del tipo
incorporado "list". El nuevo tipo será completamente compatible con
las listas regulares, pero tendrá un método adicional "increment()"
que aumenta un contador interno:

   >>> import sublist
   >>> s = sublist.SubList(range(3))
   >>> s.extend(s)
   >>> print(len(s))
   6
   >>> print(s.increment())
   1
   >>> print(s.increment())
   2

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>

   typedef struct {
       PyListObject list;
       int state;
   } SubListObject;

   static PyObject *
   SubList_increment(SubListObject *self, PyObject *unused)
   {
       self->state++;
       return PyLong_FromLong(self->state);
   }

   static PyMethodDef SubList_methods[] = {
       {"increment", (PyCFunction) SubList_increment, METH_NOARGS,
        PyDoc_STR("increment state counter")},
       {NULL},
   };

   static int
   SubList_init(SubListObject *self, PyObject *args, PyObject *kwds)
   {
       if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0)
           return -1;
       self->state = 0;
       return 0;
   }

   static PyTypeObject SubListType = {
       PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "sublist.SubList",
       .tp_doc = "SubList objects",
       .tp_basicsize = sizeof(SubListObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
       .tp_init = (initproc) SubList_init,
       .tp_methods = SubList_methods,
   };

   static PyModuleDef sublistmodule = {
       PyModuleDef_HEAD_INIT,
       .m_name = "sublist",
       .m_doc = "Example module that creates an extension type.",
       .m_size = -1,
   };

   PyMODINIT_FUNC
   PyInit_sublist(void)
   {
       PyObject *m;
       SubListType.tp_base = &PyList_Type;
       if (PyType_Ready(&SubListType) < 0)
           return NULL;

       m = PyModule_Create(&sublistmodule);
       if (m == NULL)
           return NULL;

       Py_INCREF(&SubListType);
       if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType) < 0) {
           Py_DECREF(&SubListType);
           Py_DECREF(m);
           return NULL;
       }

       return m;
   }

Como puede ver, el código fuente se parece mucho a los ejemplos
"Custom" en secciones anteriores. Desglosaremos las principales
diferencias entre ellos.

   typedef struct {
       PyListObject list;
       int state;
   } SubListObject;

La diferencia principal para los objetos de tipo derivado es que la
estructura de objeto del tipo base debe ser el primer valor. El tipo
base ya incluirá "PyObject_HEAD()" al comienzo de su estructura.

Cuando un objeto Python es una instancia de "SubList", su puntero
"PyObject *" se puede convertir de forma segura tanto en "PyListObject
*" como en "SubListObject *":

   static int
   SubList_init(SubListObject *self, PyObject *args, PyObject *kwds)
   {
       if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0)
           return -1;
       self->state = 0;
       return 0;
   }

Vemos arriba cómo llamar al método "__init__" del tipo base.

Este patrón es importante cuando se escribe un tipo con miembros
personalizados "tp_new" y "tp_dealloc". El manejador "tp_new" no
debería crear realmente la memoria para el objeto con su "tp_alloc",
pero deja que la clase base lo maneje llamando a su propio "tp_new".

La estructura "PyTypeObject" admite a "tp_base" especificando la clase
base concreta del tipo. Debido a problemas de compilación
multiplataforma, no puede llenar ese campo directamente con una
referencia a "PyList_Type"; debe hacerse más tarde en la función de
inicialización del módulo:

   PyMODINIT_FUNC
   PyInit_sublist(void)
   {
       PyObject* m;
       SubListType.tp_base = &PyList_Type;
       if (PyType_Ready(&SubListType) < 0)
           return NULL;

       m = PyModule_Create(&sublistmodule);
       if (m == NULL)
           return NULL;

       Py_INCREF(&SubListType);
       if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType) < 0) {
           Py_DECREF(&SubListType);
           Py_DECREF(m);
           return NULL;
       }

       return m;
   }

Antes de llamar a "PyType_Ready()", la estructura de tipo debe tener
el espacio "tp_base" rellenado. Cuando derivamos un tipo existente, no
es necesario completar el "tp_alloc" ranura con "PyType_GenericNew()"
-- la función de asignación del tipo base será heredada.

Después de eso, llamar a "PyType_Ready()" y agregar el objeto tipo al
módulo es lo mismo que con los ejemplos básicos "Custom".

-[ Notas al pie ]-

[1] Esto es cierto cuando sabemos que el objeto es un tipo básico,
    como una cadena o un flotador.

[2] Nos basamos en esto en el manejador "tp_dealloc" en este ejemplo,
    porque nuestro tipo no admite la recolección de basura.

[3] Ahora sabemos que el primer y el último miembro son cadenas de
    caracteres, por lo que quizás podríamos ser menos cuidadosos al
    disminuir sus recuentos de referencia, sin embargo, aceptamos
    instancias de subclases de cadenas. A pesar de que la
    desasignación de cadenas normales no volverá a llamar a nuestros
    objetos, no podemos garantizar que la desasignación de una
    instancia de una subclase de cadena de caracteres no vuelva a
    llamar a nuestros objetos.

[4] Además, incluso con nuestros atributos restringidos a instancias
    de cadenas, el usuario podría pasar subclases arbitrarias "str" y,
    por lo tanto, seguir creando ciclos de referencia.
