Search code examples
pythonctypespython-3.xpython-c-api

Create a Python type from C that implements a __dict__?


  • How is a type created to have a __dict__ as per a "normal" class would have were it defined in Python?
  • Are there any examples of non-dynamic types with __dict__s?
  • Do types defined via Python's PyTypeObject pass through type_new?

There is a tp_dict member of PyTypeObject, but I can find no information on how it's used. There also seems to be something going on in typeobject.c's type_new but I can't decipher it clearly.

Here is some related information I've found:


Solution

  • The following code will generate a class that implements a __dict__ in Python 2.x:

    typedef struct {
      PyObject_HEAD
      PyObject* dict;
    } BarObject;
    
    static PyTypeObject BarObject_Type = {
      PyObject_HEAD_INIT(NULL)
    };
    
    PyMODINIT_FUNC
    initFoo(void)
    {
      PyObject *m;
    
      m = Py_InitModule("Foo", NULL);
      if (m == NULL)
        return;
    
      BarObject_Type.tp_new = PyType_GenericNew;
      BarObject_Type.tp_name = "Foo.Bar";
      BarObject_Type.tp_basicsize = sizeof(BarObject);
      BarObject_Type.tp_getattro = PyObject_GenericGetAttr;
      BarObject_Type.tp_setattro = PyObject_GenericSetAttr;
      BarObject_Type.tp_flags = Py_TPFLAGS_DEFAULT;
      BarObject_Type.tp_dictoffset = offsetof(BarObject,dict);
      BarObject_Type.tp_doc = "Doc string for class Bar in module Foo.";
      if (PyType_Ready(&BarObject_Type) < 0)
        return;
    
      Py_INCREF(&BarObject_Type);
      PyModule_AddObject(m, "Bar", (PyObject*)&BarObject_Type);
    }
    

    The important bit is the tp_dictoffset member of the PyTypeObject struct (http://docs.python.org/c-api/typeobj.html):

    If the instances of this type have a dictionary containing instance variables, this field is non-zero and contains the offset in the instances of the type of the instance variable dictionary; this offset is used by PyObject_GenericGetAttr().

    Do not confuse this field with tp_dict; that is the dictionary for attributes of the type object itself.