Passer des listes bidimensionnelles de python à DLL

Bonjour à tous. J'ai décidé de compléter légèrement l'article C / C ++ de Python .


Passer des types standard comme int, bool, float et ainsi de suite est assez simple, mais pas très nécessaire. Python lui-même va rapidement gérer ces données, et il est peu probable que quiconque ait besoin de transférer une partie de ce code vers la bibliothèque C / C ++.


Mais le transfert de grands tableaux de données, ou encore mieux de tableaux de données bidimensionnels, ou même de tableaux d'objets bidimensionnels.


Tout ici n'est pas si évident, et il y a un certain nombre de choses qui, je pense, peuvent être mises en évidence pour ceux qui veulent accélérer considérablement les sections de code difficiles pour l'interpréteur python.


L'exemple donné sous la coupe n'est pas très utile à l'usage, mais je pense qu'il suffit de mettre en évidence toutes les nuances de cette procédure.


Donnez immédiatement le code source des fichiers de la bibliothèque.


py_list2c_array.h


#ifndef _PY_LIST_2_C_ARRAY_H_ #define _PY_LIST_2_C_ARRAY_H_ #include <stdio.h> typedef struct { int value; wchar_t* name; } Item; extern "C" __declspec(dllexport) int sum_diagonal(Item** field, size_t size); #endif 

py_list2c_array.cpp


Tout est également standard ici, sauf que je note l'utilisation de la fonction wprintf () pour imprimer des lignes comme wchar_t * .


 // py_list2c_array.cpp:      DLL. // #include "stdafx.h" #include "py_list2c_array.h" extern "C" __declspec(dllexport) int sum_diagonal(Item** field, size_t size) { int result = 0; for(size_t i=0; i<size;++i) { for(size_t j=0; j<size; ++j) { if(i == j) { result += field[i][j].value; wprintf(L"%s\n", field[i][j].name); } } } return result; } 

py_list2c_array.py


Et maintenant, la chose la plus importante. Je vais donner le code source d'un script python avec une description des points importants.


 import ctypes class PyItem: def __init__(self, value, name): self.value = value self.name = name class CItem(ctypes.Structure): _fields_ = [ ('value', ctypes.c_int), ('name', ctypes.c_wchar_p) ] def create_list(size): return [[PyItem(int(str(i+1)+str(j+1)), 'item{}{}'.format(i+1, j+1)) for j in range(size)] for i in range(size)] def py_list2c_array(py_list, size): rowType = CItem * size resultType = ctypes.POINTER(CItem) * size result = resultType() for i in range(size): row = rowType() for j in range(size): row[j] = CItem() row[j].value = py_list[i][j].value row[j].name = ctypes.c_wchar_p(py_list[i][j].name) result[i] = ctypes.cast(row, ctypes.POINTER(CItem)) return ctypes.cast(result, ctypes.POINTER(ctypes.POINTER(CItem))) if __name__ == '__main__': sLib = ctypes.cdll.LoadLibrary('./py_list2c_array.dll') size = 4 py_list = create_list(size) c_array = py_list2c_array(py_list, size) sLib.sum_diagonal.argtypes = [ctypes.POINTER(ctypes.POINTER(CItem)), ctypes.c_size_t] sLib.sum_diagonal.restype = ctypes.c_int result = sLib.sum_diagonal(c_array, ctypes.c_size_t(size)) print(': {}'.format(result)) 

Détails


Examinons quelques fonctionnalités de la création de tableaux ctypes. Pour ce faire, nous allons examiner de plus près la fonction de conversion d'une liste en tableau py_list2c_array. Vous devez d'abord spécifier les types.


Le type de chaque ligne du tableau est défini comme le type d'élément multiplié par le nombre d'éléments.


rowType = CItem * size


Un type de tableau est défini comme le type de ligne du tableau multiplié par le nombre de lignes.


Je vais expliquer un peu ci-dessous à propos de ctypes.POINTER (). ResultType = ctypes.POINTER (CItem) * size


Ensuite, créez le tableau résultant .result = resultType ()


Et dans la boucle, nous créons chaque ligne comme un tableau unidimensionnel .row = rowType ()


Ensuite, dans une boucle imbriquée, créez chaque élément du tableau et affectez des valeurs à la structure à partir de la liste des objets python.row [j] = CItem ()


ligne [j] .value = py_list [i] [j] .value
ligne [j] .name = ctypes.c_wchar_p (py_list [i] [j] .name)


Ensuite, chaque ligne créée avec des éléments doit être convertie en un type de pointeur vers un tableau d'objets et affectée à la cellule du tableau résultant.


J'écrirai un peu plus bas sur la fonction ctypes.cast () Résultat [i] = ctypes.cast (row, ctypes.POINTER (CItem))
Et bien sûr, convertissez l'ensemble du tableau en un pointeur. Retournez ctypes.cast (result, ctypes.POINTER (ctypes.POINTER (CItem)))


ctypes.POINTER


Ctypes a ctypes.POINTER () - indique qu'un pointeur est utilisé. Par exemple: ctypes.POINTER (CItem) indique qu'il s'agit d'un pointeur vers une structure CItem ().
Par conséquent, avec la ligne: ctypes.POINTER (ctypes.POINTER (CItem)), nous pouvons indiquer qu'il s'agit d'un pointeur vers un pointeur vers une structure CItem, ou en C ++ CItem ** A il y a ctypes.pointer () . Cette fonction renvoie un pointeur sur un objet. Par exemple: item = CItem ()


pointeur = ctypes.pointer (élément)


Il ne faut pas les confondre, car leur signification est complètement différente.


ctypes.cast ()


Considérons maintenant la fonction très importante ctypes.cast (). Cette fonction est quelque peu similaire à static_cast () de C ++.


Il vous permet de faire des lancers très importants.


Lors de la création d'un type de tableau, par exemple: rowType = CItem * 4


row = rowType ()


Dans ce cas, row est une zone mémoire de 4 éléments de structures CItem.


Bien entendu, sous cette forme, nous ne pourrons pas utiliser ces données. Mais si nous utilisons la fonction cast sur eux: array_pointer = ctypes.cast (row, ctypes.POINTER (CItem))


Dans ce cas, array_pointer est déjà un pointeur vers une zone mémoire avec 4 structures CItem.


Le premier paramètre est la zone de mémoire créée avec les éléments du tableau, et le second paramètre est le type vers lequel la région donnée doit être convertie. Eh bien, il semble mettre en évidence les principaux points lors du transfert de tableaux de données à l'aide de ctypes.


J'espère que cet article vous aidera à traiter plus rapidement et pleinement la merveilleuse bibliothèque ctypes.

Source: https://habr.com/ru/post/fr466575/


All Articles