Conseils pour appeler Python à partir de C

De nombreux articles ont résumé comment appeler une fonction écrite en C à partir de Python, mais j'y étais principalement accro car il y avait peu d'articles qui décrivaient en détail comment appeler une fonction de C vers Python. ・ Préparez un mémo.

Arguments de ligne de commande

Une erreur se produit lorsque quelqu'un tente de référencer un argument de ligne de commande. Si vous êtes pris dans l'erreur ci-dessus, définissez-la.

pytest.py


import sys
    if not hasattr(sys, 'argv'):
        sys.argv = ['']  #Ajoutez des arguments de ligne de commande ici si nécessaire

Chargement du module Python

En C, les parties qui sont normalement utilisées sans en avoir connaissance, comme la gestion des compteurs de référence, sont manuscrites.

callPy.c


#include <Python.h>

//Ajouter le répertoire actuel au chemin
void set_path() {
    PyObject *sys      = PyImport_ImportModule("sys");
    PyObject *sys_path = PyObject_GetAttrString(sys, "path");
    PyList_Append(sys_path, PyUnicode_DecodeFSDefault("."));
}

void main(){
    PyObject *pModule, *pFunc, *pName;
    Py_Initialize();
  set_path();
    pName = PyUnicode_DecodeFSDefault("pytest");//nom de fichier
    pModule = PyImport_Import(pName);
    Py_DECREF(pName);//Les références qui sont utilisées décrémentent le nombre de références.
    if(pModule != NULL){
        pFunc = PyObject_GetAttrString(pModule, "pyMethod");//Nom de la fonction
    }
}

Pour une raison quelconque, si vous placez le fichier Python du module à côté du fichier exécutable, il ne peut pas être lu et il semble que vous deviez ajouter le dossier actuel au chemin.

Définition de la structure

callpy.c


typedef struct{
    int val1;
    float val2;
    float val3;
    float val4;
} STRUCT2;
#define ARRAY_MAX 100
typedef struct{
    int structNo;
    STRUCT2 results[ARRAY_MAX];
} STRUCT1;

Si vous souhaitez définir une structure C comme celle ci-dessus côté Python, En Python, il est défini à l'aide de ctypes.

pytest.py


class STRUCT2(Structure):
        _fields_ = [
            ('val1', c_int32),
            ('val2', c_float),
            ('val3', c_float),
            ('val4', c_float),
        ]
class STRUCT1(Structure):
        ARRAY_MAX = 100
        _fields_ = [
            ('dataNo', c_int32),
            ('dataArray', STRUCT2 * ARRAY_MAX)
        ]

S'il s'agit d'un tableau de pointeurs au lieu d'une entité de tableau, il peut être défini comme un pointeur comme indiqué ci-dessous.

POINTER(STRUCT2) * ARRAY_MAX

Je ne suis pas satisfait d'avoir à définir la longueur du tableau comme valeur initiale même s'il s'agit de Python. Existe-t-il un moyen de le définir dynamiquement lors d'un appel depuis C?

Appeler Python depuis C

Ajoutez PyObject à Tuple dans la liste d'arguments et appelez la fonction avec CallObject

callpy.c


PyObject *pValue; //Pointeur pour la valeur de retour
Pyobject *pArgArray[3];//Prenez 3 arguments
Pyobject *pArgs = PyTuple_New(3);//Liste d'arguments
//Convertir la valeur de chaque argument en type PyObject
pArg[0] = PyUnicode_FromString("hogehoge");//Chaîne
pArg[1] = PyLong_FromLong(1000);//Valeur numérique,int
pArg[2] = PyFloat_FromDouble(0.998);//Fraction flottante
for(int i = 0; i < 3 ; i++){
   PyTuple_SetItem(pArgs, i, pArg[i]);//Définir des arguments dans la liste d'arguments
}
pValue = PyObject_CallObject(pFunc, pArgs);

Si vous souhaitez passer une structure ou un tableau multidimensionnel à Python

Par exemple, si vous souhaitez transmettre une image brute RVB 640 * 480, utilisez PyArray_SimpleNewFromData pour en faire un objet de type tableau 3D.

callpy.c


import_array();

npy_intp dims[3] = {480, 640, 3};
pArg = PyArray_SimpleNewFromData(3, dimensions, NPY_UINT8, image);

Valeur renvoyée côté C (type de valeur normale ou chaîne de caractères)

S'il s'agit d'une valeur de retour de type PyObject, elle peut être retournée de la même manière qu'une fonction Python. Bien sûr, plusieurs valeurs de retour sont OK

pytest.py


return val1, val2 #int, string

callpy.c


PyObject* pValue;
int num;
float decimal;
---Abréviation---
pValue = PyObject_CallObject(pFunc, pArgs);
int result = PyArg_ParseTuple(pValue, "is", &num, &decimal);

Il existe plusieurs façons de recevoir la valeur de retour en C, mais ParseTuple semble être bon pour le moment. Confirmer le format du type de retour à l'avance.

Valeur renvoyée côté C (structure ou tableau de structures)

S'il s'agissait d'un type ctypes comme C, j'étais accro aux essais et erreurs en pensant que je devrais simplement passer le pointeur de Python à C.

pytest.py


memoryview(mystruct).tobytes()

Quand j'ai créé un tableau d'octets comme celui-ci, il semble qu'il soit nécessaire d'en faire un type PyObject une fois car c'est un type de tableau de ctypes, et il ne peut pas être passé comme un pointeur C tel quel. Cependant, même si je l'ai passé en tant que type PyObject, je ne savais pas comment l'analyser avec c, donc je l'ai implémenté en ** passant en utilisant le type numpy.darray **.

pytest.py


return np.frombuffer(struct, c_int8)

Convertissez simplement la structure directement en type darray avec numpy.frombuffer et recevez-la sous forme de tableau numpy avec C.

callpy.c


PyArrayObject *pArray;
PyArg_ParseTuple(pValue, "O", &pArray );
STRUCT1* struct_ptr = (STRUCT1*)PyArray_DATA(pArray);

Après tout

Au début, je ne savais pas du tout comment transmettre d'énormes données, alors j'ai essayé diverses choses telles que l'utilisation du mappage de mémoire, mais à la fin, passer en tant que tableau d'octets avec numpy.darray semble être le plus rapide et le plus facile à comprendre. ..

Recommended Posts

Conseils pour appeler Python à partir de C
Remarque pour Pyjulia appelant Julia depuis Python
Envelopper C avec Cython pour une utilisation à partir de Python
~ Conseils pour les débutants de Python donnés avec amour par Pythonista ① ~
Envelopper C ++ avec Cython pour une utilisation à partir de Python
~ Conseils pour les débutants de Python donnés avec amour par Pythonista ② ~
Conseils aux débutants en Python pour utiliser l'exemple Scikit-image pour eux-mêmes 9 Utilisation à partir du langage C
[Python + Selenium] Conseils pour le grattage
~ Conseils pour les débutants de Python présentés avec amour par Pythonista ③ ~
astuces python
Appeler popcount depuis Ruby / Python / C #
Aide-mémoire Python (pour les expérimentés C ++)
[TouchDesigner] Conseils pour la déclaration par python
Exécuter du code Python à partir de l'interface graphique C #
Exécutez des scripts Python de manière synchrone à partir de C #
Appeler C / C ++ depuis Python sur Mac
Astuces Python
Astuces Python
Appeler le langage C depuis Python (python.h)
"Programmation Python AI" à partir de 0 pour Windows
Conseils pour gérer les binaires en Python
Conseils pour utiliser python + caffe avec TSUBAME
Essayez d'appeler Python depuis Ruby avec une économie
Python> Numéros de sortie de 1 à 100, 501 à 600> Pour csv
Générer un langage C à partir d'une expression S avec Python
Conseils pour créer de petits outils avec python
Utilisation des fonctions C ++ de python avec pybind11
Une introduction à Python pour les programmeurs en langage C
30/10/2016 else pour Python3> pour:
Conseils Python Conda
python [pour moi]
Conseils pour manipuler numpy.ndarray à partir de c ++ -Je veux utiliser un itérateur-
Astuces de clic Python
sql à sql
De manière inattendue (?) Connaissance du bean Python
notes de python C ++
python, openFrameworks (c ++)
Exécuter des scripts Python à partir d'applications C # GUI
Créer un tableau C à partir d'une feuille Python> Excel
Un mémorandum sur l'appel de Python à partir de Common Lisp
Conseils pour accéder à l'API ATND avec Python
Tutoriel Boost.NumPy pour l'extension de Python en C ++ (pratique)
Appelez la bibliothèque Python pour la normalisation de texte depuis MATLAB
Appel de scripts Python à partir de Python intégré en C ++ / C ++
Je veux créer du code C ++ à partir de code Python!
Appeler Polly à partir du kit SDK AWS pour Python
Remarque pour oct2py appelant le script Octave depuis Python
À propos de Python for loop
Utilisez Thingsspeak de Python
Touchez MySQL depuis Python 3
Astuces Python et Numpy
Exploitez Filemaker depuis Python
Bases de Python ② pour déclaration
Utiliser fluentd de python
Pointeur de modèle d'extension Python C / C ++
Accéder à bitcoind depuis python
Changements de Python 3.0 à Python 3.5
Changements de Python 2 à Python 3.0
Benchmarks langage C, Java, Python avec factorisation prime
Python depuis ou import
Utilisez MySQL depuis Python