注意:这不是一个问题 - 我解决了问题并在此处发布,试图分享我学到的东西。
我昨晚在使用numpy时遇到了问题,这就是我将它简化为短代码的方法。起初它看起来像是一个bug,但就在我尝试写这个问题时,我意识到这是我自己的错误。希望后来也有人能够从中受益于此问题!
使用WinSDK 7.1的C编译器在Win 7 x64上可以重复。 Python版本是3.3.3,使用MSC v.1600构建。 Numpy版本是1.8.0。
0)简要总结:当我将一个ndarray传递给我用c代码编译的dll时,c代码看到的数组与我传入的数组不同。
1)写一个c代码:
// testdll.c
#include <stdlib.h>
__declspec(dllexport) void copy_ndarray(double *array1, double *array2, size_t array_length);
void copy_ndarray(double *array1, double *array2, size_t array_length)
{
size_t i;
for(i=0; i<array_length; i++)
array2[i] = array1[i];
return;
}
2)编写一个python代码:
import numpy as np
import ctypes
# wrap the function from dll to python
lib = ctypes.cdll.LoadLibrary('./testdll.dll')
fun = lib.copy_ndarray
fun.restype = None
fun.argtypes = [np.ctypeslib.ndpointer(ctypes.c_double), np.ctypeslib.ndpointer(ctypes.c_double), ctypes.c_size_t]
# Initialize array1 and array2
array_length= 10
temp = np.c_[100.*np.ones(array_length), 200.*np.ones(array_length)]
array1 = temp[:, 1]
array2 = np.zeros(array_length)
fun(array1, array2, array_length)
3)运行代码。看看array1和array2是如何不同的。
答案 0 :(得分:3)
当然应该是不同的!
当我使用array1 = temp[:, 1]
时,array1不是真正的大小(10,)ndarray。它是temp
的视图,大小为(10,2)。想想它是如何存储在内存中的 - 当指针转到c中的另一个sizeof(double)
时,它将遇到temp
中的下一个元素,而不是array1中的下一个元素。
修复它的方法是 - 在读取数据时不要使用ndarray视图!使用此行
array1 = temp[:, 1].copy()
制作副本,而不是简单地使用视图。
正确的python代码是:
import numpy as np
import ctypes
# wrap the function from dll to python
lib = ctypes.cdll.LoadLibrary('./testdll.dll')
fun = lib.copy_ndarray
fun.restype = None
fun.argtypes = [np.ctypeslib.ndpointer(ctypes.c_double), np.ctypeslib.ndpointer(ctypes.c_double), ctypes.c_size_t]
# Initialize array1 and array2
array_length= 10
temp = np.c_[100.*np.ones(array_length), 200.*np.ones(array_length)]
array1 = temp[:, 1].copy()
array2 = np.zeros(array_length)
fun(array1, array2, array_length)
我个人认为这很棘手,因为作为一个数据分析器(说实话,我不是......我是研究员,但足够接近!),99%的时候一个视图比副本更好,因为它更快,一旦数据被读取,我们不需要原始的ndarray。
了解这一点并记住这一点很好!