2012-09-17 15 views
6

Estoy tratando de entender la implementación numpy de PEP3118. ¿Cómo funciona exactamente el acceso de buffer en numpy?numpy.getbuffer y numpy.frombuffer

>>> p = numpy.getbuffer(numpy.arange(10)) 
>>> p 
<read-write buffer for 0x1003e5b10, size -1, offset 0 at 0x1016ab4b0> 
>>> numpy.frombuffer(p) 
array([ 0.00000000e+000, 4.94065646e-324, 9.88131292e-324, 
    1.48219694e-323, 1.97626258e-323, 2.47032823e-323, 
    2.96439388e-323, 3.45845952e-323, 3.95252517e-323, 
    4.44659081e-323]) 

Así que estoy obteniendo retornos inesperados. Esperaría ver una matriz con 10 elementos de 0-9. Sin embargo, puedo entrar en la matriz y leer/escribir.

>>> j = numpy.frombuffer(p) 
>>> j 
array([ 0.00000000e+000, 4.94065646e-324, 9.88131292e-324, 
    1.48219694e-323, 1.97626258e-323, 2.47032823e-323, 
    2.96439388e-323, 3.45845952e-323, 3.95252517e-323, 
    4.44659081e-323]) 
>>> j += 1 
>>> j 
array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]) 

Parece que el búfer se está inicializando a todos los ceros, y luego puedo escribir en él. La funcionalidad que estoy esperando es poder construir la matriz (con arange o asarray) directamente en el buffer con getbuffer. ¿No es eso posible?

Respuesta

14

Tiene un problema simple dtype. El tampón se crea con

np.getbuffer(np.arange(10)) 

tiene una dtype=int, porque np.arange utiliza dtype=int por defecto.

Entonces, cuando intenta leer el buffer con

np.frombuffer(p) 

eres, de hecho, utilizando el valor por defecto de dtype=floatnp.frombuffer. En su lugar, utilice

np.frombuffer(p, dtype=int) 

et voilà, se obtiene

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
8

Permítaseme añadir algunas observaciones a la excelente answer existente por Pierre.

Es necesario getbuffer sólo si usted tiene que cortar un ndarray: se puede recuperar el objeto de búfer pitón asociado con todo el conjunto a través del atributo data

>>> import numpy as np 
>>> a = np.arange(10) 
>>> a.data == np.getbuffer(a) 
True 

Por el contrario, no es necesario pasar una objeto de búfer real a la función frombuffer, cada objeto que expone la interfaz buffer es bueno.

>>> np.frombuffer(a, a.dtype) 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
>>> np.frombuffer(a) 
array([ 0.00000000e+000, 4.94065646e-324, 9.88131292e-324, 
     1.48219694e-323, 1.97626258e-323, 2.47032823e-323, 
     2.96439388e-323, 3.45845952e-323, 3.95252517e-323, 
     4.44659081e-323]) 
>>> import array 
>>> c = array.array('i', range(10)) 
>>> np.frombuffer(c, np.int32) 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32) 
>>> np.frombuffer(c) 
array([ 2.12199579e-314, 6.36598737e-314, 1.06099790e-313, 
     1.48539705e-313, 1.90979621e-313]) 

Cuando decodificación un objeto de memoria intermedia, que tiene que saber la correcta dtype como demuestran los ejemplos anteriores. Para ser más precisos, los objetos de memoria intermedia no tienen un dtype: son solo una secuencia de datos binarios. En cambio, los objetos ndarray tienen un dtype que dicta cómo se interpretan los datos binarios subyacentes.

Para responder a su pregunta: cada numpy ndarray expone la interfaz del búfer. Puede acceder al búfer o a una porción del mismo a través del descriptor data o la función getbuffer. Puede crear ndarray del objeto exponiendo la interfaz del búfer por medio de la función frombuffer. Dado que el búfer (a diferencia de ndarrays) no tiene información dtype, siempre debe especificar explícitamente cómo se debe interpretar el búfer a través del argumento dtype al frombuffer.

+0

¡Qué admirable apéndice a la respuesta de Pierre!El detalle adicional es bastante apreciado. – Jzl5325