Cree un tipo Python desde C que implemente un __dict__?

  • ¿Cómo se crea un tipo para tener un __dict__ según una clase “normal” si se definiera en Python?
  • ¿Hay ejemplos de tipos no dynamics con __dict__ s?
  • ¿Los tipos definidos a través de PyTypeObject de Python pasan a través de type_new ?

Hay un miembro tp_dict de PyTypeObject , pero no puedo encontrar información sobre cómo se usa. También parece haber algo en el typeobject.c de type_new pero no puedo descifrarlo claramente.

Aquí hay alguna información relacionada que he encontrado:

  • __dict__ en la clase heredada del módulo de extensión C
  • ¿Cómo se implementa __slots__ en Python?

El siguiente código generará una clase que implementa un __dict__ en 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); } 

El bit importante es el miembro tp_dictoffset de la estructura PyTypeObject ( http://docs.python.org/c-api/typeobj.html ):

Si las instancias de este tipo tienen un diccionario que contiene variables de instancia, este campo es distinto de cero y contiene el desplazamiento en las instancias del tipo del diccionario de variables de instancia; este desplazamiento es utilizado por PyObject_GenericGetAttr ().

No confunda este campo con tp_dict; ese es el diccionario para los atributos del tipo objeto en sí.

Para responder primero a la última pregunta: No, type_new solo se usa para “tipos de stack” que se definen dinámicamente en tiempo de ejecución (por ejemplo, a través de una statement de clase). Los tipos definidos estáticamente se inicializan utilizando PyType_Ready() lugar.

Para responder su primera pregunta: para crear un tipo de extensión con un descriptor __dict__ , debe asignar dinámicamente el tipo de la misma manera que lo hace el intérprete para una definición de clase.

Una forma de obtener ejemplos para eso es hacer lo que John sugiere y generar algunos ejemplos propios con Cython.

Para CPython 2.x puede consultar el método build_class en el código fuente de CPython ( http://svn.python.org/view/python/trunk/Python/ceval.c?view=markup ) para tener una idea del Pasos implicados en una solución totalmente general.

Sin embargo, si está utilizando Python 3, esta pregunta puede ser interesante: ¿Qué hace Python builtin __build_class__?

Es decir, como una solución específica de CPython 3.x, lo más sencillo es llamar builtins.__build_class__ con los argumentos adecuados a través de la API de C.

No he hecho esto, soy terriblemente malo en el uso de C-API, pero de acuerdo con los documentos, debería ser suficiente con el uso de PyObject_GenericGetAttr y PyObject_GenericSetAttr para los métodos getattro y setattro . También necesita tener un atributo de __dict__ llamado __dict__ por supuesto.

¿Has probado eso?

¿Qué tal si escribes un código Python definiendo una clase y uno o dos métodos, compilándolo con Cython e inspeccionando el código C generado?