L'obtention de données de ctypes array numpy
Je suis à l'aide d'un Python (via ctypes
) enveloppé de la bibliothèque C pour exécuter une série de calcul. À différentes étapes de la course, je veux obtenir des données en Python, et plus précisément numpy
tableaux.
L'emballage, je suis en utilisant n'deux types différents de retour pour un tableau de données (qui est d'un intérêt particulier pour moi):
-
ctypes
Tableau: Quand je faistype(x)
(où x est lectypes
tableau, je reçois un<class 'module_name.wrapper_class_name.c_double_Array_12000'>
en retour. Je sais que ces données est une copie des données internes de la documentation et je suis capable d'en faire unenumpy
tableau facilement:>>> np.ctypeslib.as_array(x)
Cela renvoie d'un 1D numpy
tableau de données.
-
ctype
pointeur vers les données: Dans ce cas, à partir de la bibliothèque, de la documentation, je comprends que je suis un pointeur vers les données stockées et utilisées directement à la bibliothèque. La Whey je netype(y)
(où y est le pointeur), j'ai<class 'module_name.wrapper_class_name.LP_c_double'>
. Avec ce cas, je suis toujours en mesure d'indexer les données commey[0][2]
, mais je n'ai pu l'obtenir dans numpy par l'intermédiaire d'un super maladroit:>>> np.frombuffer(np.core.multiarray.int_asbuffer( ctypes.addressof(y.contents), array_length*np.dtype(float).itemsize))
J'ai trouvé ça dans un vieux numpy
liste de diffusion fil de Travis Oliphant, mais pas dans le numpy
de la documentation. Si, au lieu de cette approche que j'ai essayer comme ci-dessus, je reçois le texte suivant:
>>> np.ctypeslib.as_array(y)
...
... BUNCH OF STACK INFORMATION
...
AttributeError: 'LP_c_double' object has no attribute '__array_interface__'
Est-ce np.frombuffer
approche la meilleure ou la seule façon de le faire? Je suis ouvert à d'autres suggestions, mais doit souhaitez tout de même utiliser numpy
que j'ai beaucoup de post-traitement de code qui repose sur numpy
fonctionnalités que je veux utiliser ces données.
- Vous avez le contrôle sur le C lib? Pourriez-vous changer l'API de la bibliothèque?
- Oui - je avoir la source. Je ne suis pas sûr de la façon d'aller bien, comme le pointeur approche permet de Python à agir directement sur les données qui, je suppose, dans certains cas, pourrait être un avantage. Dans mon cas, oui, il y aurait avantage d'avoir tout sortir comme un
ctype
tableau. Toutes les recommandations? - Je vous propose de faire de la bibliothèque un (NumPy-) de la matrice de vous allouer en Python et passer à la bibliothèque. De cette façon, vous pouvez agir sur la même mémoire, mais vous n'avez pas à s'embêter à faire tout maladroit conversions. Vous disposez déjà d'un tableau NumPy, et en passant à une bibliothèque est bien pris en charge par l'aide de
numpy.ctypeslib.ndpointer
comme type d'argument à la ctypes wrapper de votre fonction. (Si ce n'est pas clair, il suffit de demander...)
Vous devez vous connecter pour publier un commentaire.
La création de tableaux NumPy à partir d'un ctypes pointeur d'objet est un problème de fonctionnement. Il est difficile de savoir qui est le propriétaire de la mémoire que le pointeur pointe. Quand il sera libéré à nouveau? Combien de temps est-il valable? Chaque fois que possible je voudrais essayer d'éviter ce genre de construction. Il est tellement plus facile et plus sûr de créer des tableaux dans le code Python et les passer à la fonction C de l'utilisation de la mémoire allouée par un Python n'est pas au courant C de la fonction. En faisant de ce dernier, vous nier, dans une certaine mesure les avantages d'avoir un langage de haut niveau en prenant soin de la gestion de la mémoire.
Si vous êtes vraiment sûr que quelqu'un prend soin de la mémoire, vous pouvez créer un objet d'exposer le Python "protocole de mémoire", puis créer un tableau NumPy à l'aide de ce tampon d'objet. Vous a donné un moyen de créer de la mémoire tampon d'objet dans votre post, via les sans-papiers
int_asbuffer()
fonction:(À noter que j'ai remplacé
8
pournp.dtype(float).itemsize
. C'est toujours 8, sur toute plate-forme.) Une autre façon de créer de la mémoire tampon de l'objet serait d'appeler lePyBuffer_FromMemory()
fonction de l'Python API C via ctypes:Pour ces deux méthodes, vous pouvez créer un tableau NumPy de
buffer
par(En fait, je ne comprends pas pourquoi vous utilisez
.astype()
au lieu d'un deuxième paramètre àfrombuffer
; en outre, je me demande pourquoi vous utiliseznp.int
, alors que vous avez dit plus tôt que le tableau contientdouble
s.)J'ai peur de ne pas obtenir beaucoup plus facile que cela, mais il n'est pas mauvais en soit, vous ne pensez pas? Vous pourriez enterrer toutes les laide de détails dans un wrapper de la fonction et de ne pas s'inquiéter plus.
.astype()
appel était juste un accident de la copie et de la dernière erreur. J'ai sorti de ma question maintenant. Merci pour ramasser sur que.PyMemoryView_FromMemory
, pasPyBuffer_FromMemory
. Beaucoup de choses qui étaient auparavant appelés tampons sont maintenant appelés memoryviews.Une autre possibilité (ce qui peut nécessiter plus récentes versions de bibliothèques que ce qui est disponible lors de la première réponse a été écrit -- j'ai testé quelque chose de similaire avec
ctypes 1.1.0
etnumpy 1.5.0b2
) est de convertir le pointeur vers le tableau.Cela semble encore avoir la propriété partagée de la sémantique, alors vous avez probablement besoin pour vous assurer que vous gratuit le sous-jacent de la mémoire tampon par la suite.
y
pointeur vers un pointeur vers un tableau de type:ap = ctypes.cast(y, ctypes.POINTER(ArrayType))
oùArrayType = ctypes.c_double * array_length
et de créer un tableau numpy: ila = np.frombuffer(ap.contents)
. Voir Comment convertir le pointeur de c tableau de python arrayAucune de ces fonctionné pour moi en Python 3. Comme une solution générale pour la conversion d'un ctypes pointeur dans un numpy ndarray en python 2 et 3, j'ai trouvé ce travail (via l'obtention de lecture de la mémoire tampon):
np.ctypeslib.as_array
est tout ce dont vous avez besoin ici.À partir d'un tableau:
À partir d'un pointeur
Si vous êtes ok avec la création de tableaux en python, l'exemple suivant avec un tableau 2d fonctionne en python3:
numpy et ctypes versions sont 1.11.1 et 1.1.0