2

I wonder how can I define a static class variable from C++ for Python? The equivalent Python code would be like:

class foo:
    bar = int

I tried to use tp_getset field when defining the type, but it turns out it doesn't work and returns a getset_descriptor in Python, and it doesn't work when called on instances (AttributeError). Furthermore, Python doc says directly manipulating tp_dict with C API is unsafe. But it doesn't tell what to use instead. (see here)

I deliberately chose int in the example since I'm referencing some other class in it, if that matters.

YiFei
  • 1,752
  • 1
  • 18
  • 33

1 Answers1

2

The tp_getset defines descriptors for a type; descriptors are bound to instances when accessed via the __getattribute__ hook, so are not suitable to define class attributes.

You can add attributes to a class by setting them on the PyTypeObject.tp_dict object for the type; do so in the module's initialization function (PyInit_<modulename>), for example, after finalising the type with PyType_Ready() (which makes sure the tp_dict object exists):

PyObject *d;
PyObject *bar;

d = PyFoo_Type.tp_dict;

bar = PyLong_FromLong(42);
if (bar == NULL || PyDict_SetItemString(d, "bar", bar) < 0)
    return NULL;
Py_DECREF(bar);

This is untested C code; I'm not familiar enough with C++ to confidently provide you with a C++ version instead.

If you want to see a real-life example, see the datetime module, where the datetime.min, datetime.max, etc. class attributes are set.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Can I say that it's safe to modify `tp_dict` directly before I call `PyModule_AddObject`? – YiFei Sep 09 '17 at 17:55
  • @YiFei: I believe so; there is an interaction with `PyObject_SetAttrString()` that's not supported, but modifying `tp_dict` in module initialisers is used in multiple places in the Python codebase. – Martijn Pieters Sep 09 '17 at 17:57
  • @YiFei: for example, the `sys` module *deletes* entries from `tp_dict` objects for specific types (removing `__new__` methods to prevent new instances). – Martijn Pieters Sep 09 '17 at 17:59