Create an object using Python's C API
Asked Answered
T

1

52

Say I have my object layout defined as:

typedef struct {
    PyObject_HEAD
    // Other stuff...
} pyfoo;

...and my type definition:

static PyTypeObject pyfoo_T = {
    PyObject_HEAD_INIT(NULL)
    // ...

    pyfoo_new,
};

How do I create a new instance of pyfoo somewhere within my C extension?

Traverse answered 12/11, 2010 at 9:6 Comment(0)
S
59

Call PyObject_New(), followed by PyObject_Init().

EDIT: The best way is to call the class object, just like in Python itself:

/* Pass two arguments, a string and an int. */
PyObject *argList = Py_BuildValue("si", "hello", 42);

/* Call the class object. */
PyObject *obj = PyObject_CallObject((PyObject *) &pyfoo_T, argList);

/* Release the argument list. */
Py_DECREF(argList);
Streptococcus answered 12/11, 2010 at 9:10 Comment(12)
I agree the docs are a little terse in that case. I updated my answer with the required call to PyObject_Init().Vow
Wait, PyObject_Init() doesn't take any arguments, so how do you pass in the requisite initialisation arguments?Traverse
@detly, you need to call the class object. See my updated answer.Vow
Aah, that makes more sense. Is it normal to get a compiler error ("assignment from incompatible pointer type")?Traverse
@detly, since PyTypeObject "derives" from PyObject internally, and an explicit cast is used, there should be no warning. What's your compiler?Vow
GCC 4.4.5... and now that I've had a chance to check, it's only a warning, not an error.Traverse
If returning this instance to a Python function, I'm assuming I don't need to increment the retain count to be safe?Immunochemistry
@jkp, if I'm not mistaken, the class object should already have INCREFed the object it returned, because it just created it and intends to pass ownership to you in the first place. If you also intend to pass ownership of the new object to your caller, you should not DECREF it either. See edcjones.tripod.com/refcount.html for the gory details.Vow
one-liner: PyObject_CallFunction((PyObject *)&pyfoo_T, "si", "hello", 42); combines PyObject_CallObject + Py_BuildValueCapable
If there is only one argument, the Py_BuildValue call needs parenthesis in the format string.Scrogan
Can you expand on what you mean by "best"? Is there any reason to prefer CallObject over PyObject_New and PyObject_Init which are crossed out in the answer?Prosit
Is this answer out of date? I can't find it in documentationAvalokitesvara

© 2022 - 2024 — McMap. All rights reserved.