In vielen Artikeln wurde zusammengefasst, wie eine in C geschriebene Funktion von Python aus aufgerufen wird, aber ich war hauptsächlich davon abhängig, da es nur wenige Artikel gab, in denen ausführlich beschrieben wurde, wie eine Funktion von C nach Python aufgerufen wird. ・ Stellen Sie ein Memo zusammen.
Ein Fehler tritt auf, wenn jemand versucht, auf ein Befehlszeilenargument zu verweisen. Wenn Sie in den obigen Fehler geraten, definieren Sie ihn.
pytest.py
import sys
if not hasattr(sys, 'argv'):
sys.argv = [''] #Fügen Sie hier bei Bedarf Befehlszeilenargumente hinzu
In C sind die Teile, die normalerweise ohne Kenntnis verwendet werden, wie z. B. die Handhabung von Referenzzählern, handgeschrieben.
callPy.c
#include <Python.h>
//Aktuelles Verzeichnis zum Pfad hinzufügen
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");//Dateiname
pModule = PyImport_Import(pName);
Py_DECREF(pName);//Verwendete Referenzen verringern den Referenzzähler.
if(pModule != NULL){
pFunc = PyObject_GetAttrString(pModule, "pyMethod");//Funktionsname
}
}
Wenn Sie die Python-Datei des Moduls neben die ausführbare Datei stellen, kann sie aus irgendeinem Grund nicht gelesen werden, und Sie müssen anscheinend den aktuellen Ordner zum Pfad hinzufügen.
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;
Wenn Sie eine C-Struktur wie die oben auf der Python-Seite definieren möchten, In Python wird es mit ctypes definiert.
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)
]
Wenn es sich um ein Zeigerarray anstelle einer Arrayentität handelt, kann es wie unten gezeigt als Zeiger definiert werden.
POINTER(STRUCT2) * ARRAY_MAX
Ich bin unzufrieden damit, dass ich die Array-Länge als Anfangswert definieren muss, obwohl es Python ist. Gibt es eine Möglichkeit, es dynamisch zu definieren, wenn Sie von C aus anrufen?
callpy.c
PyObject *pValue; //Zeiger für Rückgabewert
Pyobject *pArgArray[3];//Nimm 3 Argumente
Pyobject *pArgs = PyTuple_New(3);//
//Konvertieren Sie den Wert jedes Arguments in den PyObject-Typ
pArg[0] = PyUnicode_FromString("hogehoge");//String
pArg[1] = PyLong_FromLong(1000);//Numerischer Wert,int
pArg[2] = PyFloat_FromDouble(0.998);//Schwimmende Fraktion
for(int i = 0; i < 3 ; i++){
PyTuple_SetItem(pArgs, i, pArg[i]);//Legen Sie Argumente in der Argumentliste fest
}
pValue = PyObject_CallObject(pFunc, pArgs);
Wenn Sie beispielsweise ein 640 * 480 RGB-Rohbild übergeben möchten, verwenden Sie PyArray_SimpleNewFromData, um es zu einem Objekt vom Typ 3D-Array zu machen.
callpy.c
import_array();
npy_intp dims[3] = {480, 640, 3};
pArg = PyArray_SimpleNewFromData(3, dimensions, NPY_UINT8, image);
Wenn es sich um einen Rückgabewert vom Typ PyObject handelt, kann er auf dieselbe Weise wie eine Python-Funktion zurückgegeben werden. Natürlich sind mehrere Rückgabewerte in Ordnung
pytest.py
return val1, val2 #int, string
callpy.c
PyObject* pValue;
int num;
float decimal;
---Abkürzung---
pValue = PyObject_CallObject(pFunc, pArgs);
int result = PyArg_ParseTuple(pValue, "is", &num, &decimal);
Es gibt verschiedene Möglichkeiten, den Rückgabewert in C zu erhalten, aber ParseTuple scheint vorerst gut zu sein. Bestätigen das Format des Rückgabetyps im Voraus.
Wenn es ein Typ vom Typ c wie C war, war ich süchtig nach Versuch und Irrtum und dachte, ich sollte nur den Zeiger von Python an C übergeben.
pytest.py
memoryview(mystruct).tobytes()
Wenn ich ein Byte-Array wie dieses erstellt habe, scheint es notwendig zu sein, es einmal zu einem PyObject-Typ zu machen, da es sich um einen Array-Typ von c-Typen handelt und nicht so wie er ist als C-Zeiger übergeben werden kann. Selbst wenn ich es als PyObject-Typ übergeben habe, wusste ich nicht, wie ich es mit c analysieren soll, also habe ich es implementiert, indem ich es mit dem Typ numpy.darray übergeben habe.
pytest.py
return np.frombuffer(struct, c_int8)
Konvertieren Sie die Struktur einfach direkt in den Darray-Typ mit numpy.frombuffer und empfangen Sie sie als numpy-Array mit C.
callpy.c
PyArrayObject *pArray;
PyArg_ParseTuple(pValue, "O", &pArray );
STRUCT1* struct_ptr = (STRUCT1*)PyArray_DATA(pArray);
Anfangs wusste ich überhaupt nicht, wie man große Datenmengen übergibt, also habe ich verschiedene Dinge ausprobiert, wie beispielsweise die Verwendung der Speicherzuordnung, aber am Ende scheint die Übergabe als Byte-Array mit numpy.darray am schnellsten und am einfachsten zu verstehen zu sein. ..
Recommended Posts