Fortunately, most scientists can simply use the buffer protocol via tools like NumPy without knowing too much of the details of what's behind it. Because the buffer protocol is fundamentally a C-API entity, implementing new functionality with it generally requires digging into the guts of Python's C API. For example, the code that enables the above numpy example is found in NumPy's buffer.c file, and reading through it is not particularly enlightening. This is the power of Python in a nutshell: it abstracts away C-level messiness like this and instead gives us the nice, powerful, and clean Python interface we all know and love.

But sometimes you need to get your hands dirty. Imagine, for instance, that you have a C object that you'd like to wrap and make available to Python. Your first course might be to use something like f2py, cython, or SWIG to do this: I'd definitely recommend these tools for most problems of this nature.

But you may, for various reasons, want to go even deeper and implement the buffer protocol directly. (For example, you may be interested in taking data structures from another language, such as Julia, and exposing them to Python in a flexible manner). Below I'll give you an example of how to do this.