◐ Shell
clean mode source ↗

Message 151347 - Python tracker

Currently, there's no straightforward way to create new classes in Python that delegate the PEP 3118 buffer APIs to another object that supports them (e.g. bytes, bytearray, memoryview, array.array, a NumPy array).

I see a few possible ways to go about this:

1. Add a single new special method, __buffer__. This creates an entry in the underlying getbuffer slot, but leaves releasebuffer empty.

The getbuffer wrapper then calls __buffer__ and delegates the getbuffer call to the returned object.

Any created Py_buffer instances refer directly to the underlying PEP 3118 supporting object, not the original object that defines __buffer__

The downside of this approach is that you can't implement a completely new PEP 3118 supporting object in pure Python (since you don't get access to the flags)

2. As above, but any Py_buffer structs returned are updated to refer to the original object, not the underlying one. A releasebuffer wrapper is also created, that calls back into __buffer__ to retrieve the object again. This approach has problems if __buffer__ can change to refer to different objects over time.

3. Define separate __getbuffer__ and __releasebuffer__ special methods. All C types implementing the PEP 3118 slots get these special methods automatically (as with any other slot). The flag variables are passed into __getbuffer__, and it is expected to return a memoryview object defining the view. The underlying getbuffer slot wrapper stores the current object in the Py_buffer "obj" slot, and the returned memoryview in "internal". The rest of the Py_buffer fields are populated based on the memoryview contents.

The releasebuffer wrapper then reverses this process, by passing the memoryview instance from the internal slot into the __releasebuffer__ call.