23.06.20 12:18, Victor Stinner пише:
For example, we can consider continuing to provide raw access to a PyObject** array, but an object can reply "sorry, I don't support this PyObject** protocol". Also, I expect to have a function call to notify the object when the PyObject** view is not longer needed. Something like Py_buffer protocol PyBuffer_Release(). Maybe an object can generate a temporary PyObject** view which requires to allocate resources (like memory) and the release function would release these resources.
Pseudo-code:
void iterate(PyObject *obj) { PyObjectPP_View view;
if (PyObjectPP_View_Get(&view, obj)) { // fast-path: the object provides a PyObject** view for (Py_ssize_t i=0; i < view.len; i++ { PyObject *item = view.array[i]; ... } PyObjectPP_View_Release(&view); } else { // slow code path using PySequence_GetItem() or anything else ... }
Maybe PyObjectPP_View_Get() should increment the object reference counter to ensure that the object cannot be destroyed in the loop (if the loop calls arbitrary Python code), and PyObjectPP_View_Release() would decrement its reference counter.
It is not enough. A list can change content and size during iteration. You need either add the "export" count which prevent list mutating, or copy the list, or use such tricks as temporary swapping its content with the empty list for the time of iteration. In all cases it is a user visible change in behavior.
"PyObjectPP_View" protocol looks like PySequence_Fast() API, but IMO PySequence_Fast() is not generic enough. For example, the first issue is that it cannot reply "no, sorry, the object doesn't support PyObject**". It always creates a temporary list if the object is not a tuple or a list, that may be inefficient for a large sequence.
If you want to avoid conversion to a list, you can check that the object is a tuple or a list before using PySequence_Fast*() API. I don't see a need for new API for this.
Also, the "view" protocol should be allowed to query other types than just PyObject**. For example, what if I would like to iterate on a sequence of integers? bytes, array.array and memoryview can be seen as sequences of integers.
Were not the buffer protocol and the memoryview object designed for this? In Python you can call `memoryview(obj).cast('I')` and then iterate integers. I think there is something similar in C.