[Python-Dev] Py_ssize_t backwards compatibility

"Martin v. Löwis" martin at v.loewis.de
Sat Mar 18 08:59:36 CET 2006

Thomas Heller wrote:
>  #if (PY_VERSION_HEX < 0x02050000)
>  typedef int Py_ssize_t;
>  #define lenfunc inquiry
>  #define readbufferproc getreadbufferproc
>  #define writebufferproc getwritebufferproc
>  #define segcountproc getsegcountproc
>  #define charbufferproc getcharbufferproc
>  #define ssizeargfunc intargfunc
>  #define ssizessizeargfunc intintargfunc
>  #define ssizeobjargproc intobjargproc
>  #define ssizessizeobjargproc intintobjargproc
>  ... more defines
>  #endif

Thinking about this, I now believe (again) that this isn't
what people should do. Instead, they should avoid these
type names altogether, and should avoid casting function

The reason they currently do that is because of the self
pointer: the self pointer should have the specific type,
instead of being PyObject*, so that you can access the fields
of the object.

The reason they should avoid this is that this casting is
error-prone: If they make a mistake in the signature
(e.g. forget to replace int with Py_ssize_t), the compiler
will not tell them. This happened to me a few times while
converting modules to Py_ssize_t; you need to be very
careful when using these casts.

OTOH, the solution to avoid them is pretty mechanic, and
straight-forward. Just drop the casts, and replace

Py_ssize_t foo_len(Foo* self)


Py_ssize_t foo_len(PyObject* _self)
  Foo* self = (Foo*)_self;

Then, foo_len will already have the type lenfunc, and
no cast is required. If you have also

#if (PY_VERSION_HEX < 0x02050000)
typedef int Py_ssize_t;

then this code will work unmodified in earlier versions:
foo_len will be of type int (*)(PyObject*), which is
precisely the type inquiry that it should have in the
earlier versions.



for an example of applying this approach to ctypes.


More information about the Python-Dev mailing list