C-API, tp_dictoffset vs tp_members

Ulrich Eckhardt doomster at knuut.de
Sun Jul 26 05:45:37 EDT 2009


"Martin v. Löwis" wrote:
>> I have a predefined set of members, some of which are optional.
> 
> Having optional fields is also a good reason.

What is the use of T_OBJECT_EX vs T_OBJECT in PyMemberDef then? I would
 have though that the former describes an optional field, because the
 behaviour of accessing it when it is NULL is the same as accessing a
 nonexistent field. However, I see that it still appears in the dir()
 output even if it is NULL, so it seems I'm misunderstanding this.

>> The problem
>> I had with an embedded dictionary was that I can't see its elements using
>> "dir()".
> 
> How so? That should work fine.

>>> import example
>>> x = example.Example()
>>> dir(x)
['__class__', '__delattr__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__str__']
>>> x.example_attribute
'example value'

The 'example_attribute' can be accessed, but it is not visible in the
dir() output. The code for this is below.


>> Now I just converted to using tp_members, and it still seems to
>> work correctly for the cases I tested.
> 
> So how do you do optional fields now? In particular, how would you do
> optional integers?

See above, I would expect T_OBJECT_EX to do that.

Thanks!

Uli



/* example.c

 gcc -Wall example.c -shared -I /usr/include/python2.5 -o example.so
*/

#include <Python.h>
#include <structmember.h>

typedef struct {
    PyObject_HEAD
    PyObject* dict;
} Example;

static void
Example_dealloc(PyObject* self)
{
    Example* ex = (Example*)self;
    Py_XDECREF(ex->dict);
    self->ob_type->tp_free(self);
}

static PyObject *
Example_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    Example* self;
    PyObject* attr;

    self = (Example*)type->tp_alloc(type, 0);
    if(self==NULL)
        return NULL;

    self->dict = PyDict_New();
    if(self->dict==NULL) {
        Py_DECREF(self);
        return NULL;
    }

    attr = PyString_FromString("example value");
    if(PyObject_SetAttrString((PyObject*)self, "example_attribute", attr)<0) {
        Py_DECREF(self);
        return NULL;
    }

    return (PyObject*)self;
}

static PyTypeObject ExampleType = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "example.Example",         /*tp_name*/
    sizeof(Example),           /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    Example_dealloc,           /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,        /*tp_flags*/
    0,                         /* tp_doc */
    0,                         /* tp_traverse */
    0,                         /* tp_clear */
    0,                         /* tp_richcompare */
    0,                         /* tp_weaklistoffset */
    0,                         /* tp_iter */
    0,                         /* tp_iternext */
    0,                         /* tp_methods */
    0,                         /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    offsetof(Example, dict),   /* tp_dictoffset */
    0,                         /* tp_init */
    0,                         /* tp_alloc */
    Example_new,               /* tp_new */
};

void
initexample(void) 
{
    PyObject* m;

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

    m = Py_InitModule3("example", 0,
                       "Example module that creates an extension type.");

    if (m == NULL)
      return;

    Py_INCREF(&ExampleType);
    PyModule_AddObject(m, "Example", (PyObject*)&ExampleType);
}




More information about the Python-list mailing list