Description: Type-specific Attribute Management
Keywords: ext

### 2.2.3.2 Type-specific Attribute Management

For simplicity, only the `char*` version will be demonstrated here; the type of the name parameter is the only difference between the `char*` and `PyObject*` flavors of the interface. This example effectively does the same thing as the generic example above, but does not use the generic support added in Python 2.2. The value in showing this is two-fold: it demonstrates how basic attribute management can be done in a way that is portable to older versions of Python, and explains how the handler functions are called, so that if you do need to extend their functionality, you'll understand what needs to be done.

The `tp_getattr` handler is called when the object requires an attribute look-up. It is called in the same situations where the `__getattr__()` method of a class would be called.

A likely way to handle this is (1) to implement a set of functions (such as `newdatatype_getSize()` and `newdatatype_setSize()` in the example below), (2) provide a method table listing these functions, and (3) provide a getattr function that returns the result of a lookup in that table. The method table uses the same structure as the `tp_methods` field of the type object.

Here is an example:

    static PyMethodDef newdatatype_methods[] = {
        {"getSize", (PyCFunction)newdatatype_getSize, METH_VARARGS,
         "Return the current size."},
        {"setSize", (PyCFunction)newdatatype_setSize, METH_VARARGS,
         "Set the size."},
        {NULL, NULL, 0, NULL}           /* sentinel */
    };

    static PyObject *
    newdatatype_getattr(newdatatypeobject *obj, char *name)
    {
        return Py_FindMethod(newdatatype_methods, (PyObject *)obj, name);
    }

The `tp_setattr` handler is called when the `__setattr__()` or `__delattr__()` method of a class instance would be called. When an attribute should be deleted, the third parameter will be `NULL`. Here is an example that simply raises an exception; if this were really all you wanted, the `tp_setattr` handler should be set to `NULL`.

    static int
    newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v)
    {
        (void)PyErr_Format(PyExc_RuntimeError, "Read-only attribute: \%s", name);
        return -1;
    }