4

The Python/C API has a number of related functions that perform similar operations where one is usually for general use and another is somehow more efficient or convenient for a specific situation.

For example, PyDict_SetItem and PyDict_SetItemString are the same but the latter is specialized for a C string as a key. For PyList_SetItem and PyList_SET_ITEM, the second has no error checking and doesn't decref the existing item (explained here).

But what is the reason for having special conversions like PyInt_FromLong when there is always Py_BuildValue? Both return a new reference to a Python object and seem to do the exact same thing. This same question applies to functions like PyInt_FromSsize_t, PyTuple_Pack, etc. (all compared to Py_BuildValue with the appropriate format string of course).

When should you use one over the other?

Community
  • 1
  • 1
Jared
  • 25,627
  • 7
  • 56
  • 61
  • 1
    You could view `Py_BuildValue` as a result of the [facade pattern](http://en.wikipedia.org/wiki/Facade_pattern). It's an high level call that puts together a lot of low-level calls. It isn't required, but it is useful. Obviously having a single function `Py_BuildValue` without the low-level API you'd end up with a monster of hundreds or more line of code to maintain, so you *must* do the other way round: have low-level conversion APIs and a facade function for high-level access, which is much shorter and maintainable. – Bakuriu Jul 14 '13 at 06:04

1 Answers1

4

For me, it is a trade-off between performance and simplicity. For code that I've written, I tend to use Py_BuildValue when I don't care about the running time (i.e. returning a set of values that won't change, or the running time is so long the extra overhead doesn't matter.) For performance critical functions, especially those that can be at the innermost level of a loop, I will use the use lowest level API call that I can.

Whether it is worth it or not is a different question. I'll never recoup the time I've spent trying to get the best performance but I know other applications that use my code are measurably faster.

casevh
  • 11,093
  • 1
  • 24
  • 35
  • Why is `Py_BuildValue` simpler? It requires a few more keystrokes for a long. And if `PyInt_FromLong` is faster, why doesn't `Py_BuildValue` just call that directly? – Jared Jul 14 '13 at 02:26
  • 2
    I only use `Py_BuildValue` when I want to create a tuple, normally as the return value of a function but also when calling other C API functions. When returning a tuple from a performance critical function, I'll actually create an empty tuple and then set the tuple values. That is faster than calling `Py_BuildValue("(NN)",...)` but requires more lines of code. When just creating a single value, I always use the low-level function directly. `Py_BuildValue` does call `PyInt_FromLong` but it has to parse the string first, check how many values are needed, etc. It is slightly slower. – casevh Jul 14 '13 at 02:52
  • Thanks. Your comment, along with Bakuriu's, was the real answer I was looking for but I'll still mark this as the correct answer. – Jared Jul 15 '13 at 06:07