3.3.3 Riferimenti deboli nei tipi

Uno degli obiettivi dell'implementazione è quello di permettere ad ogni tipo di partecipare al meccanismo dei riferimenti deboli senza generare l'overhead su quegli oggetti che non beneficiano di questo meccanismo (come i numeri).

Affinché un oggetto sia riferibile in modo debole, l'estensione deve includere nella struttura dell'istanza un campo PyObject* per l'utilizzo del meccanismo dei riferimenti deboli; questo deve venire inizializzato a NULL dal costruttore dell'oggetto. Deve anche impostare il campo tp_weaklistoffset del corrispondente tipo di oggetto dell'offset del campo. Inoltre, deve aggiungere Py_TPFLAGS_HAVE_WEAKREFS allo slot tp_flags. Per esempio, l'istanza tipo viene definita con la seguente struttura:

typedef struct {
    PyObject_HEAD
    PyClassObject *in_class;       /* L'oggetto classe */
    PyObject      *in_dict;        /* Un dizionario */
    PyObject      *in_weakreflist; /* Lista di riferimenti deboli */
} PyInstanceObject;

L'oggetto tipo dichiarato staticamente per le istanze viene così definito:

PyTypeObject PyInstance_Type = {
    PyObject_HEAD_INIT(&PyType_Type)
    0,
    "module.instance",

    /* Molte righe omesse per brevità... */

    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS   /* tp_flags */
    0,                                          /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    0,                                          /* tp_richcompare */
    offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */
};

Il costruttore di tipo è responsabile dell'inizializzazione della lista dei riferimenti deboli come NULL:

static PyObject *
instance_new() {
    /* Altre righe di inizializzazione omesse per brevità */

    self->in_weakreflist = NULL;

    return (PyObject *) self;
}

L'unica aggiunta ulteriore è che il distruttore ha bisogno di chiamare il gestore dei riferimenti deboli per pulire ogni riferimento debole rimasto. Questo deve essere fatto prima di ogni altra cosa, da parte del distruttore, ma vien richiesto solamente se la lista dei riferimenti deboli è non NULL:

static void
instance_dealloc(PyInstanceObject *inst)
{
    /* Allocate temporaneamente se necessario, ma non
       iniziate ancora la distruzione.
     */

    if (inst->in_weakreflist != NULL)
        PyObject_ClearWeakRefs((PyObject *) inst);

    /* Procedete normalmente con la distruzione dell'oggetto. */
}
Vedete Circa questo documento... per informazioni su modifiche e suggerimenti.