Olá pessoal. Decidi complementar um pouco o artigo C / C ++ do Python .
Passar tipos padrão como int, bool, float e assim por diante é bem simples, mas não muito necessário. O próprio Python lidará rapidamente com esses dados e é improvável que alguém precise transferir parte desse código para a biblioteca C / C ++.
Mas a transferência de grandes matrizes de dados, ou ainda melhores matrizes de dados bidimensionais, ou mesmo matrizes bidimensionais de objetos.
Tudo aqui não é tão óbvio, e acho que há várias coisas que podem ser destacadas para quem deseja acelerar significativamente as seções de código difíceis para o interpretador python.
O exemplo dado no corte não é muito útil para uso, mas acho que é suficiente para destacar todas as nuances desse procedimento.
Forneça imediatamente o código fonte dos arquivos da biblioteca.
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
Tudo também é padrão aqui, exceto pelo fato de eu observar o uso da função wprintf () para imprimir linhas como wchar_t * .
py_list2c_array.py
E agora a coisa mais importante. Vou dar o código fonte de um script python com uma descrição de pontos importantes.
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))
Detalhes
Vamos considerar alguns recursos da criação de matrizes ctypes. Para fazer isso, examinaremos mais de perto a função de converter uma lista na matriz py_list2c_array. Você deve especificar os tipos primeiro.
O tipo de cada linha na matriz é definido como o tipo de elemento multiplicado pelo número de elementos.
rowType = CItem * tamanho
Um tipo de matriz é definido como o tipo de linha da matriz vezes o número de linhas.
Vou explicar um pouco abaixo sobre ctypes.POINTER (). ResultType = ctypes.POINTER (CItem) * tamanho
Em seguida, crie a matriz resultante .result = resultType ()
E no loop, criamos cada linha como um array unidimensional .row = rowType ()
Em seguida, em um loop aninhado, crie cada elemento da matriz e atribua valores à estrutura da lista de objetos python.row [j] = CItem ()
linha [j] .value = py_list [i] [j] .value
linha [j] .name = ctypes.c_wchar_p (py_list [i] [j] .name)
Em seguida, cada linha criada com elementos deve ser convertida em um tipo de ponteiro para uma matriz de objetos e atribuída à célula da matriz resultante.
Vou escrever um pouco mais sobre a função ctypes.cast () Resultado [i] = ctypes.cast (linha, ctypes.POINTER (CItem))
E, é claro, converta toda a matriz em um ponteiro.Retorno ctypes.cast (result, ctypes.POINTER (ctypes.POINTER (CItem)))
ctypes.POINTER
Ctypes possui ctypes.POINTER () - indica que um ponteiro está sendo usado. Por exemplo: ctypes.POINTER (CItem) indica que é um ponteiro para uma estrutura CItem ().
Assim, com a linha: ctypes.POINTER (ctypes.POINTER (CItem)), podemos indicar que é um ponteiro para um ponteiro para uma estrutura CItem, ou no C ++ CItem ** A, existe ctypes.pointer () . Esta função retorna um ponteiro para um objeto. Por exemplo: item = CItem ()
ponteiro = ctypes.pointer (item)
Eles não devem ser confundidos, pois seu significado é completamente diferente.
ctypes.cast ()
Agora considere a função muito importante ctypes.cast (). Essa função é um pouco semelhante à static_cast () do C ++.
Permite fazer elencos muito importantes.
Ao criar um tipo de matriz, por exemplo: rowType = CItem * 4
row = rowType ()
Nesse caso, a linha é uma área de memória de 4 elementos das estruturas do CItem.
Obviamente, neste formulário, não poderemos usar esses dados. Mas se usarmos a função de conversão neles: array_pointer = ctypes.cast (linha, ctypes.POINTER (CItem))
Nesse caso, array_pointer já é um ponteiro para uma área de memória com 4 estruturas CItem.
O primeiro parâmetro é a área de memória criada com elementos de matriz, e o segundo parâmetro é o tipo para o qual a região especificada deve ser convertida .. Bem, parece destacar os pontos principais ao transferir matrizes de dados usando ctypes.
Espero que este artigo o ajude de maneira mais rápida e completa com a maravilhosa biblioteca de ctypes.