Message 248111 - Python tracker (original) (raw)

A functional memoryview for ctypes objects would avoid having to use workarounds, such as the following:

>>> d = ctypes.c_double()
>>> b = (ctypes.c_char * ctypes.sizeof(d)).from_buffer(d)
>>> b[:] = b'abcdefgh'
>>> d.value
8.540883223036124e+194

or using numpy.frombuffer as a bridge:

>>> d = ctypes.c_double()
>>> m = memoryview(numpy.frombuffer(d, 'B'))
>>> m[:] = b'abcdefgh'
>>> d.value
8.540883223036124e+194

David's request that cast('B') should be made to work for all contiguous buffers seems reasonable. That said, the ctypes format strings also need fixing. Let's see what happens when "@d" is used instead of "<d":

>>> double_stgdict = stgdict(ctypes.c_double)
>>> double_stgdict
dict: 
    ob_base: 
        ob_refcnt: 1
        ob_type: py_object(<class 'StgDict'>)
    ma_used: 7
    ma_keys: LP_PyDictKeysObject(0x1aa5750)
    ma_values: LP_LP_PyObject(<NULL>)
size: 8
align: 8
length: 0
ffi_type_pointer: 
    size: 8
    alignment: 8
    type: 3
    elements: <NULL>
proto: py_object('d')
setfunc: SETFUNC(0x7f9f9b6e3e60)
getfunc: GETFUNC(0x7f9f9b6e3d90)
paramfunc: PARAMFUNC(0x7f9f9b6e31d0)
argtypes: py_object(<NULL>)
converters: py_object(<NULL>)
restype: py_object(<NULL>)
checker: py_object(<NULL>)
flags: 4096
format: b'<d'
ndim: 0
shape: LP_c_long(<NULL>)

>>> double_stgdict.format = b'@d'

>>> d = ctypes.c_double(3.14)
>>> m = memoryview(d)
>>> m[()]
3.14
>>> m[()] = 6.28
>>> d.value
6.28

>>> m = m.cast('B')
>>> m[:] = b'abcdefgh'
>>> d.value
8.540883223036124e+194

This shows that changing the format string (set by PyCSimpleType_new in _ctypes.c) to use "@" makes the memoryview work normally. OTOH, the swapped type (e.g. c_double.ctype_be) would need to continue to use a standard little-endian ("<") or big-endian (">") format.