ãããã¡ãããã³ã« (buffer Protocol)¶
Pythonã§å©çšå¯èœãªããã€ãã®ãªããžã§ã¯ãã¯ãäžå±€ã«ããã¡ã¢ãªé
åãŸã㯠buffer ãžã®ã¢ã¯ã»ã¹ãæäŸããŸãããã®ãããªãªããžã§ã¯ããšããŠãçµã¿èŸŒã¿ã® bytes ã bytearray ã array.array ã®ãããªããã€ãã®æ¡åŒµåãæããããŸãããµãŒãããŒãã£ã®ã©ã€ãã©ãªã¯ç»ååŠçãæ°å€è§£æã®ãããªç¹å¥ãªç®çã®ããã«ããããèªèº«ã®åãå®çŸ©ããããšãã§ããŸãã
ããããã®åã¯ããèªèº«ã®ã»ãã³ãã£ã¯ã¹ãæã¡ãŸããããããã倧ããªã¡ã¢ãªãããã¡ãããªããšããå ±éã®ç¹åŸŽãå ±æããŸããããã€ãã®ç¶æ³ã§ã¯ä»²ä»ããã³ããŒãè¡ãããšãªãçŽæ¥ãããã¡ã«ã¢ã¯ã»ã¹ããããšãæãŸããŸãã
Python provides such a facility at the C and Python level in the form of the buffer protocol. This protocol has two sides:
on the producer side, a type can export a "buffer interface" which allows objects of that type to expose information about their underlying buffer. This interface is described in the section ãããã¡ãªããžã§ã¯ãæ§é äœ (buffer object structure); for Python see Emulating buffer types.
on the consumer side, several means are available to obtain a pointer to the raw underlying data of an object (for example a method parameter). For Python see
memoryview.
bytes ã bytearray ãªã©ã®ã·ã³ãã«ãªãªããžã§ã¯ãã¯ãå
éšã®ãããã¡ãŒããã€ãåã®åœ¢åŒã§å
¬éããŸãã
ãã€ãå以å€ã®åœ¢åŒãå©çšå¯èœã§ããäŸãã°ã array.array ãå
¬éããèŠçŽ ã¯ãã«ããã€ãå€ã«ãªãããšããããŸãã
bufferã€ã³ã¿ãŒãã§ãŒã¹ã®å©çšè
ã®äžäŸã¯ããã¡ã€ã«ãªããžã§ã¯ãã® write() ã¡ãœããã§ã: bufferã€ã³ã¿ãŒãã§ãŒã¹ãéããŠäžé£ã®ãã€ãåãæäŸã§ããã©ããªãªããžã§ã¯ãã§ããã¡ã€ã«ã«æžã蟌ãããšãã§ããŸãã write() ã¯ããã®åŒæ°ãšããŠæž¡ããããªããžã§ã¯ãã®å
éšèŠçŽ ã«å¯Ÿããèªã¿åºãå°çšã¢ã¯ã»ã¹ã®ã¿ãå¿
èŠãšããŸããã readinto() ã®ãããªä»ã®ã¡ãœããã§ã¯ããã®åŒæ°ã®å
容ã«å¯Ÿããæžã蟌ã¿ã¢ã¯ã»ã¹ãå¿
èŠã§ããbufferã€ã³ã¿ãŒãã§ãŒã¹ã«ããããªããžã§ã¯ãã¯èªã¿æžãäž¡æ¹ãèªã¿åºãå°çšãããã¡ãžã®ã¢ã¯ã»ã¹ãèš±å¯ããããããšãæåŠãããéžæããããšãã§ããŸãã
bufferã€ã³ã¿ãŒãã§ãŒã¹ã®å©çšè ã«ã¯ã察象ãšãªããªããžã§ã¯ãã®ãããã¡ãåŸãäºã€ã®æ¹æ³ããããŸã:
æ£ããåŒæ°ã§
PyObject_GetBuffer()ãåŒã³åºã;PyArg_ParseTuple()(ãŸãã¯ãã®åæã®ã²ãšã€) ãy*ãw*ãŸãã¯s*format codes ã®ãããããšãšãã«åŒã³åºãã
ã©ã¡ãã®ã±ãŒã¹ã§ããbufferãå¿
èŠãªããªã£ãæã« PyBuffer_Release() ãåŒã³åºããªããã°ãªããŸããããããæ ããšããªãœãŒã¹ãªãŒã¯ã®ãããªæ§ã
ãªåé¡ã«ã€ãªããæãããããŸãã
Added in version 3.12: The buffer protocol is now accessible in Python, see
Emulating buffer types and memoryview.
buffer æ§é äœÂ¶
ãããã¡æ§é äœïŒãŸãã¯åçŽã« "buffers"ïŒã¯å¥ã®ãªããžã§ã¯ãã®ãã€ããªããŒã¿ãPythonããã°ã©ãã«æäŸããã®ã«äŸ¿å©ã§ããããã¯ãŸãããŒãã³ããŒã¹ã©ã€ã·ã³ã°æ©æ§ãšããŠã䜿çšã§ããŸãããã®ã¡ã¢ãªãããã¯ãåç §ããæ©èœã䜿ãããšã§ãã©ããªããŒã¿ã§ããšãŠãç°¡åã«Pythonããã°ã©ãã«æäŸããããšãã§ããŸããã¡ã¢ãªã¯ãC æ¡åŒµã®å€§ããªé å宿°ãããããŸãããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã©ã€ãã©ãªã«æž¡ãåã®ã¡ã¢ãªãããã¯ãããããŸããããæ§é åããŒã¿ããã€ãã£ãã®ã€ã³ã¡ã¢ãªåœ¢åŒåãæž¡ãã®ã«äœ¿çšããããããããŸããã
Pythonã€ã³ã¿ããªã¿ã«ãã£ãŠæäŸãããå€ãã®ããŒã¿åãšã¯ç°ãªãããããã¡ã¯ PyObject ãã€ã³ã¿ã§ã¯ãªããã·ã³ãã«ãªC æ§é äœã§ãããã®ãããäœæãšã³ããŒãéåžžã«ç°¡åã«è¡ããŸãããããã¡ã®äžè¬çãªã©ãããŒãå¿
èŠãªãšãã¯ã memoryview ãªããžã§ã¯ããäœæãããŸãã
ãšã¯ã¹ããŒãããããªããžã§ã¯ããæžãæ¹æ³ã®çã説æã«ã¯ã Buffer Object Structures ãåç
§ããŠãã ããããããã¡ãååŸããã«ã¯ã PyObject_GetBuffer() ãåç
§ããŠãã ããã
-
type Py_buffer¶
- 次ã«å±ããŸã: Stable ABI (ãã¹ãŠã®ã¡ã³ããŒãå«ã) (ããŒãžã§ã³ 3.11 ãã).
-
void *buf¶
ãããã¡ãã£ãŒã«ãã衚ããŠããè«çæ§é ã®å é ãæããã€ã³ã¿ã ãããã¡ãæäŸãããªããžã§ã¯ãã®äžå±€ç©çã¡ã¢ãªãããã¯äžã®ã©ã®äœçœ®ã«ããªãããŸãã äŸãã°
stridesãè² ã ãšããã®å€ã¯ã¡ã¢ãªãããã¯ã®æ«å°ŸãããããŸãããé£ç¶ é åã®å Žåãã®å€ã¯ã¡ã¢ãªãããã¯ã®å é ãæããŸãã
-
PyObject *obj¶
ãšã¯ã¹ããŒã察象ãªããžã§ã¯ããžã®æ°ããåç §ããã®åç §ã¯æ¶è²»è ã«ãã£ãŠææãããèªåçã«è§£æŸãããŸãïŒã€ãŸããåç §ã«ãŠã³ããæžå°ããŸãïŒããèšå®ãããŸã
NULLbyPyBuffer_Release(). ãã®ãã£ãŒã«ãã¯ãæšæºã®C-API颿°ã®æ»ãå€ã«çžåœããŸããPyMemoryView_FromBuffer()ãŸãã¯PyBuffer_FillInfo()ã«ãã£ãŠã©ããããã äžæç㪠ãããã¡ã§ããç¹å¥ãªã±ãŒã¹ã§ã¯ããã®ãã£ãŒã«ãã¯NULLã§ããäžè¬çã«ããšã¯ã¹ããŒããªããžã§ã¯ãã¯ãã®æ¹åŒã䜿çšããŠã¯ãªããŸããã
-
Py_ssize_t len¶
product(shape) * itemsizeãcontiguousé åã§ã¯ãäžå±€ã®ã¡ã¢ãªãããã¯ã®é·ãã«ãªããŸããécontiguous é åã§ã¯ãcontiguous衚çŸã«ã³ããŒãããå Žåã«è«çæ§é ããã€é·ãã§ãã((char *)buf)[0]ãã((char *)buf)[len-1]ã®ç¯å²ãžã®ã¢ã¯ã»ã¹ã¯ãé£ç¶æ§ (contiguity) ãä¿èšŒãããªã¯ãšã¹ãã«ãã£ãŠååŸããããããã¡ã«å¯ŸããŠã®ã¿èš±ãããŸãã å€ãã®å Žåã«ããã®ãããªãªã¯ãšã¹ãã¯PyBUF_SIMPLEãŸãã¯PyBUF_WRITABLEã§ãã
-
int readonly¶
ãããã¡ãèªã¿åºãå°çšã§ããã瀺ããŸãããã®ãã£ãŒã«ãã¯
PyBUF_WRITABLEãã©ã°ã§å¶åŸ¡ã§ããŸãã
-
Py_ssize_t itemsize¶
èŠçŽ äžã€åã®byteåäœã®ãµã€ãºã
struct.calcsize()ãéNULLã®formatå€ã«å¯ŸããŠåŒã³åºããçµæãšåãã§ããéèŠãªäŸå€: æ¶è²»è ã
PyBUF_FORMATãã©ã°ãèšå®ããããšãªããããã¡ãèŠæ±ããå Žåãformatã¯NULLã«èšå®ãããŸãã ãããitemsizeã¯å ã®ãã©ãŒãããã«åŸã£ãå€ãä¿æããŸããshapeãååšããå Žåãproduct(shape) * itemsize == lenã®çåŒãå®ãããå©çšè ã¯itemsizeã buffer ãèªãããã«å©çšã§ããŸããPyBUF_SIMPLEãŸãã¯PyBUF_WRITABLEã§èŠæ±ããçµæãshapeãNULLã§ããã°ãæ¶è²»è ã¯itemsizeãç¡èŠããŠitemsize == 1ãšèŠãªããªããã°ãªããŸããã
-
char *format¶
A NULL terminated string in
structmodule style syntax describing the contents of a single item. If this isNULL,"B"(unsigned bytes) is assumed.ãã®ãã£ãŒã«ãã¯
PyBUF_FORMATãã©ã°ã«ãã£ãŠå¶åŸ¡ãããŸãã
-
int ndim¶
The number of dimensions the memory represents as an n-dimensional array. If it is
0,bufpoints to a single item representing a scalar. In this case,shape,stridesandsuboffsetsMUST beNULL. The maximum number of dimensions is given byPyBUF_MAX_NDIM.
-
Py_ssize_t *shape¶
ã¡ã¢ãªäžã®N次å é åã®åœ¢ã瀺ããé·ãã
ndimã§ããPy_ssize_tã®é åã§ããshape[0] * ... * shape[ndim-1] * itemsizeã¯lenãšçãããªããã°ãªããŸãããshape ã®å€ã¯
shape[n] >= 0ã«å¶éãããŸããshape[n] == 0ã®å Žåã«ç¹ã«æ³šæãå¿ èŠã§ãã 詳现㯠complex arrays ãåç §ããŠãã ãããshepe (圢ç¶) é åã¯å©çšè ããã¯èªã¿åºãå°çšã§ãã
-
Py_ssize_t *strides¶
忬¡å ã«ãããŠæ°ããå€ãåŸãããã«ã¹ããããããã€ãæ°ã瀺ããé·ã
ndimã®Py_ssize_tã®é åãã¹ãã©ã€ãå€ã¯ãä»»æã®æŽæ°ãæå®ã§ããŸããèŠå®ã®é åã§ã¯ãã¹ãã©ã€ãã¯éåžžã§ããã°æå¹ã§ãããããå©çšè ã¯ã
strides[n] <= 0ã®ã±ãŒã¹ãåŠçããããšãã§ããå¿ èŠããããŸãã詳现ã«ã€ããŠã¯ complex arrays ãåç §ããŠãã ãããæ¶è²»è ã«ãšã£ãŠããã® strides é åã¯èªã¿åºãå°çšã§ãã
-
Py_ssize_t *suboffsets¶
Py_ssize_tåã®èŠçŽ ãæã€é·ãndimã®é åãsuboffsets[n] >= 0ã®å Žåã¯ã n çªç®ã®æ¬¡å ã«æ²¿ã£ãŠä¿åãããŠããå€ã¯ãã€ã³ã¿ã§ã suboffset å€ã¯åãã€ã³ã¿ã®åç §ã解決ããåŸã«äœãã€ãå ããã°ãããã瀺ããŠããŸãã suboffset ã®å€ãè² ã®æ°ã®å Žåã¯ããã€ã³ã¿ã®åç §è§£æ±ºã¯äžèŠ (é£ç¶ããã¡ã¢ãªãããã¯å ã«çŽæ¥é 眮ãããã) ãšããããšã«ãªããŸããå šãŠã® suboffset ãè² æ°ã®å Žå (ã€ãŸãåç §è§£æ±ºãäžèŠ) ãªå Žåããã®ãã£ãŒã«ãã¯
NULL(ããã©ã«ãå€) ã§ãªããã°ãªããŸããããã®çš®ã®é å衚çŸã¯ Python Imaging Library (PIL) ã§äœ¿ãããŠããŸãã ãã®ãããªé åã§èŠçŽ ã«ã¢ã¯ã»ã¹ããæ¹æ³ã«ã€ããŠããã«è©³ãããšã¯ complex arrays ãåç §ããŠãã ããã
æ¶è²»è ã«ãšã£ãŠãsuboffsets é åã¯èªã¿åºãå°çšã§ãã
-
void *internal¶
ãããã¡ãæäŸããåŽã®ãªããžã§ã¯ããå éšçã«å©çšããããã®å€æ°ã§ããäŸãã°ãæäŸåŽã¯ãã®å€æ°ã«æŽæ°åããã£ã¹ãããŠãshape, strides, suboffsets ãšãã£ãé åããããã¡ãéæŸãããšãã«åæã«è§£æŸããã¹ããã©ããã管çãããã©ã°ã«äœ¿ãããšãã§ããã§ãããããããã¡ãåãåãåŽã¯ããã®å€ã決ããŠå€æŽããŠã¯ãªããŸããã
-
void *buf¶
Constants:
-
PyBUF_MAX_NDIM¶
- 次ã«å±ããŸã: Stable ABI (ããŒãžã§ã³ 3.11 ãã).
The maximum number of dimensions the memory represents. Exporters MUST respect this limit, consumers of multi-dimensional buffers SHOULD be able to handle up to
PyBUF_MAX_NDIMdimensions. Currently set to 64.
ãããã¡ãªã¯ãšã¹ãã®ã¿ã€ã¶
ãããã¡ã¯éåžžã PyObject_GetBuffer() ã䜿ãããšã§ããšã¯ã¹ããŒããããªããžã§ã¯ãã«ãããã¡ãªã¯ãšã¹ããéãããšã§åŸãããŸããã¡ã¢ãªã®è«ççãªæ§é ã®è€éæ§ã¯å€å²ã«ããããããæ¶è²»è
㯠flags åŒæ°ã䜿ã£ãŠãèªèº«ãæ±ãããããã¡ã®çš®é¡ãæå®ããŸãã
Py_buffer ã®å
šãã£ãŒã«ãã¯ããªã¯ãšã¹ãã®çš®é¡ã«ãã£ãŠææ§ããæ®ããã«å®çŸ©ãããŸãã
ãªã¯ãšã¹ãã«äŸåããªããã£ãŒã«ã¶
äžèšã®ãã£ãŒã«ã㯠flags ã®åœ±é¿ãåããã«ãåžžã«æ£ããå€ã§èšå®ãããŸãã: obj, buf, len, itemsize, ndim.
readonly, format¶
- PyBUF_WRITABLE¶
- 次ã«å±ããŸã: Stable ABI (ããŒãžã§ã³ 3.11 ãã).
Controls the
readonlyfield. If set, the exporter MUST provide a writable buffer or else report failure. Otherwise, the exporter MAY provide either a read-only or writable buffer, but the choice MUST be consistent for all consumers. For example, PyBUF_SIMPLE | PyBUF_WRITABLE can be used to request a simple writable buffer.
- PyBUF_WRITEABLE¶
This is an alias to
PyBUF_WRITABLE.Soft deprecated since version 3.13.
- PyBUF_FORMAT¶
- 次ã«å±ããŸã: Stable ABI (ããŒãžã§ã³ 3.11 ãã).
formatãã£ãŒã«ããå¶åŸ¡ããŸãããããã©ã°ãèšå®ãããŠããã°ããã®ãã£ãŒã«ããæ£ããåããªããã°ãªããŸããããã©ã°ãèšå®ãããŠããªããã°ããã®ãã£ãŒã«ããNULLã«èšå®ããªããã°ãªããŸããã
PyBUF_WRITABLE ã¯ã次ã®ç¯ã«åºãŠããã©ã®ãã©ã°ãšã | ãåã£ãŠããŸããŸããã
PyBUF_SIMPLE 㯠0 ãšå®çŸ©ãããŠããã®ã§ã PyBUF_WRITABLE ã¯åçŽãªæžã蟌ã¿å¯èœãªãããã¡ãèŠæ±ããåç¬ã®ãã©ã°ãšããŠäœ¿ããŸãã
PyBUF_FORMAT must be |'d to any of the flags except PyBUF_SIMPLE, because
the latter already implies format B (unsigned bytes). PyBUF_FORMAT cannot be
used on its own.
shape, strides, suboffsets¶
ãã®ãã©ã°ã¯ã以äžã§è€éæ§ã倧ããé ã«äžŠã¹ãã¡ã¢ãªã®è«ççãªæ§é ãå¶åŸ¡ããŸããåã ã®ãã©ã°ã¯ãããããäžã«èšèŒããããã©ã°ã®ãã¹ãŠã®ããããå«ãããšã«æ³šæããŠãã ããã
ãªã¯ãšã¹ã |
shape |
strides |
suboffsets |
|---|---|---|---|
|
yes |
yes |
å¿ èŠãªå Žå |
|
yes |
yes |
NULL |
|
yes |
NULL |
NULL |
|
NULL |
NULL |
NULL |
飿¥æ§ã®ãªã¯ãšã¹ã¶
ã¹ãã©ã€ãã®æ å ±ããã£ãŠããªããŠããC ãŸã㯠Fortran ã® é£ç¶æ§ ãæç¢ºã«èŠæ±ãããå¯èœæ§ããããŸãã ã¹ãã©ã€ãæ å ±ãªãã«ããããã¡ãŒã¯ C ãšé£æ¥ããŠããå¿ èŠããããŸãã
ãªã¯ãšã¹ã |
shape |
strides |
suboffsets |
contig |
|---|---|---|---|---|
|
yes |
yes |
NULL |
C |
|
yes |
yes |
NULL |
F |
|
yes |
yes |
NULL |
C ã F |
yes |
NULL |
NULL |
C |
è€åãªã¯ãšã¹ã¶
æãåŸãå šãŠã®ãªã¯ãšã¹ãã®å€ã¯ãåã®ç¯ã§ã®ãã©ã°ã®çµã¿åããã§ç¶²çŸ çã«å®çŸ©ãããŠããŸãã 䟿å©ãªããã«ããããã¡ãŒãããã³ã«ã§ã¯é »ç¹ã«äœ¿çšãããçµã¿åãããåäžã®ãã©ã°ãšããŠæäŸããŠãŸãã
次ã®ããŒãã«ã® U ã¯é£ç¶æ§ãæªå®çŸ©ã§ããããšã衚ããŸãã
å©çšè
㯠PyBuffer_IsContiguous() ãåŒã³åºããŠé£ç¶æ§ãå€å®ããå¿
èŠãããã§ãããã
ãªã¯ãšã¹ã |
shape |
strides |
suboffsets |
contig |
readonly |
format |
|---|---|---|---|---|---|---|
|
yes |
yes |
å¿ èŠãªå Žå |
U |
0 |
yes |
|
yes |
yes |
å¿ èŠãªå Žå |
U |
1 ã 0 |
yes |
|
yes |
yes |
NULL |
U |
0 |
yes |
|
yes |
yes |
NULL |
U |
1 ã 0 |
yes |
|
yes |
yes |
NULL |
U |
0 |
NULL |
|
yes |
yes |
NULL |
U |
1 ã 0 |
NULL |
|
yes |
NULL |
NULL |
C |
0 |
NULL |
|
yes |
NULL |
NULL |
C |
1 ã 0 |
NULL |
è€éãªé å¶
NumPy ã¹ã¿ã€ã«: shape, strides¶
NumPy ã¹ã¿ã€ã«ã®é
åã®è«ççæ§é 㯠itemsize, ndim, shape, strides ã§å®çŸ©ãããŸãã
ndim == 0 ã®å Žåã¯ã buf ãæãã¡ã¢ãªã®å Žæã¯ããµã€ãºã itemsize ã®ã¹ã«ã©å€ãšããŠè§£éãããŸãã
ãã®å Žåã shape ãš strides ã®äž¡æ¹ãšã NULL ã§ãã
strides ã NULL ã®å Žåã¯ãé
åã¯æšæºã® n 次å
C é
åãšããŠè§£éãããŸãã
ããã§ãªãå Žåã¯ãå©çšè
ã¯æ¬¡ã®ããã« n 次å
é
åã«ã¢ã¯ã»ã¹ããªããã°ãªããŸãã:
ptr = (char *)buf + indices[0] * strides[0] + ... + indices[n-1] * strides[n-1];
item = *((typeof(item) *)ptr);
äžèšã®ããã«ã buf ã¯ã¡ã¢ãªãããã¯å
ã®ã©ã®å Žæã§ãæãããšãå¯èœã§ãããšã¯ã¹ããŒã¿ãŒã¯ãã®é¢æ°ã䜿çšããããšã«ãã£ãŠãããã¡ã®åŠ¥åœæ§ã確èªåºæ¥ãŸãã
def verify_structure(memlen, itemsize, ndim, shape, strides, offset):
"""Verify that the parameters represent a valid array within
the bounds of the allocated memory:
char *mem: start of the physical memory block
memlen: length of the physical memory block
offset: (char *)buf - mem
"""
if offset % itemsize:
return False
if offset < 0 or offset+itemsize > memlen:
return False
if any(v % itemsize for v in strides):
return False
if ndim <= 0:
return ndim == 0 and not shape and not strides
if 0 in shape:
return True
imin = sum(strides[j]*(shape[j]-1) for j in range(ndim)
if strides[j] <= 0)
imax = sum(strides[j]*(shape[j]-1) for j in range(ndim)
if strides[j] > 0)
return 0 <= offset+imin and offset+imax+itemsize <= memlen
PIL ã¹ã¿ã€ã«: shape, strides, suboffsets¶
PIL ã¹ã¿ã€ã«ã®é
åã§ã¯éåžžã®èŠçŽ ã®ä»ã«ãããæ¬¡å
ã®äžã§æ¬¡ã®èŠçŽ ãååŸããããã«èŸ¿ããã€ã³ã¿ãæãŠãŸãã
äŸãã°ãéåžžã®3次å
C é
å char v[2][2][3] ã¯ã2次å
é
åãžã® 2 ã€ã®ãã€ã³ã¿ãããªãé
å char (*v[2])[2][3] ãšèŠãããšãã§ããŸãã
suboffset 衚çŸã§ã¯ããããã® 2 ã€ã®ãã€ã³ã¿ã¯ buf ã®å
é ã«åã蟌ããã¡ã¢ãªã®ã©ãã«ã§ãé
眮ã§ãã 2 ã€ã® char x[2][3] é
åãæããŸãã
次ã®äŸã¯ã strides ã suboffsets ã NULL ã§ãªãå Žåã®ãN 次å
ã€ã³ããã¯ã¹ã«ãã£ãŠæãããŠãã N 次å
é
åå
ã®èŠçŽ ãžã®ãã€ã³ã¿ãè¿ã颿°ã§ã:
void *get_item_pointer(int ndim, void *buf, Py_ssize_t *strides,
Py_ssize_t *suboffsets, Py_ssize_t *indices) {
char *pointer = (char*)buf;
int i;
for (i = 0; i < ndim; i++) {
pointer += strides[i] * indices[i];
if (suboffsets[i] >=0 ) {
pointer = *((char**)pointer) + suboffsets[i];
}
}
return (void*)pointer;
}