ctypes - Anfänger

100

Ich habe die Aufgabe, eine AC-Bibliothek in eine Python-Klasse zu "verpacken". Die Dokumente sind in dieser Angelegenheit unglaublich vage. Es scheint, dass sie erwarten, dass nur fortgeschrittene Python-Benutzer ctypes implementieren würden. Nun, ich bin ein Anfänger in Python und brauche Hilfe.

Eine Schritt-für-Schritt-Hilfe wäre wunderbar.

Also habe ich meine c Bibliothek. Was mache ich? Welche Dateien lege ich wo ab? Wie importiere ich die Bibliothek? Ich habe gelesen, dass es eine Möglichkeit gibt, Python automatisch zu verpacken.

(Übrigens habe ich das ctypes-Tutorial auf python.net gemacht und es funktioniert nicht. Das heißt, ich denke, sie gehen davon aus, dass ich in der Lage sein sollte, den Rest der Schritte auszufüllen.

In der Tat ist dies der Fehler, den ich mit ihrem Code bekomme:

File "importtest.py", line 1
   >>> from ctypes import *
   SyntaxError: invalid syntax

Ich könnte wirklich eine Schritt-für-Schritt-Hilfe gebrauchen! Danke ~

verbrachteak
quelle
10
Haben Sie die >>> in importtest.py? Wenn Personen eine Postleitzahl >>> in jeder Zeile eingeben, bedeutet dies, dass sie in der interaktiven Shell ausgeführt wird. Um es aus einer Datei auszuführen, entfernen Sie >>> (das sind 3> Zeichen und ein Leerzeichen), wo immer es erscheint.
Chinmay Kanchi
4
Geben Sie nicht das >>>s ein. Diese werden von der interaktiven Shell gedruckt und sollten nicht in Ihrer Quelldatei enthalten sein.
Nmichaels
8
>>>in der .py Datei! AUTSCH! Noch nie gesehen!
David Heffernan
3
Um ehrlich zu sein, lernen Sie ein bisschen Python (zumindest ein bisschen), bevor Sie anfangen, sich mit ctypes zu beschäftigen. Sie werden niemals ein Tutorial zu ctypes finden, das davon ausgeht, dass Sie kein grundlegendes Python kennen.
Chinmay Kanchi
3
@spentak: Wenn Sie um Hilfe bitten, geben Sie angemessene Informationen an. Zeigen Sie uns zumindest die letzte Version des Codes, über den Sie sprechen. Was steht zum Beispiel in "Zeile 3"?
Francesco

Antworten:

227

Hier ist ein schnelles und schmutziges ctypes-Tutorial.

Schreiben Sie zuerst Ihre C-Bibliothek. Hier ist ein einfaches Beispiel für eine Hallo-Welt:

testlib.c

#include <stdio.h>

void myprint(void);

void myprint()
{
    printf("hello world\n");
}

Kompilieren Sie es jetzt als gemeinsam genutzte Bibliothek ( Mac-Fix hier ):

$ gcc -shared -Wl,-soname,testlib -o testlib.so -fPIC testlib.c

# or... for Mac OS X 
$ gcc -shared -Wl,-install_name,testlib.so -o testlib.so -fPIC testlib.c

Schreiben Sie dann einen Wrapper mit ctypes:

testlibwrapper.py

import ctypes

testlib = ctypes.CDLL('/full/path/to/testlib.so')
testlib.myprint()

Führen Sie es jetzt aus:

$ python testlibwrapper.py

Und Sie sollten die Ausgabe sehen

Hello world
$

Wenn Sie bereits eine Bibliothek im Sinn haben, können Sie den Nicht-Python-Teil des Tutorials überspringen. Stellen Sie sicher, dass ctypes die Bibliothek finden kann, indem Sie sie in ein /usr/libanderes Standardverzeichnis stellen. In diesem Fall müssen Sie beim Schreiben des Wrappers nicht den vollständigen Pfad angeben. Wenn Sie dies nicht tun, müssen Sie beim Aufruf den vollständigen Pfad der Bibliothek angeben ctypes.CDLL().

Dies ist nicht der richtige Ort für ein umfassenderes Tutorial. Wenn Sie jedoch bei bestimmten Problemen auf dieser Website um Hilfe bitten, hilft Ihnen die Community sicher weiter.

PS: Ich gehe davon aus, dass Sie unter Linux arbeiten, weil Sie verwendet haben ctypes.CDLL('libc.so.6'). Wenn Sie ein anderes Betriebssystem verwenden, können sich die Dinge ein wenig (oder ziemlich viel) ändern.

Chinmay Kanchi
quelle
1
@ Chinmay: Kann ich einen ähnlichen Code für Windows haben und könnten Sie anstelle von C bitte ein visuelles C ++ - Beispiel bereitstellen? Ich kann meine Bibliothek laden, aber ich kann nicht über die DLL-Datei auf meine Funktionen zugreifen. Es steht immer "Funktion 'xyz' nicht gefunden". Könnten Sie mir einen Weg vorschlagen, dies zu umgehen? Prost.
Neophile
Ich weiß nicht viel über die Windows-Entwicklung, aber es sieht so aus, als ob Windows etwas Wonky macht, vielleicht verwendet es eine andere Aufrufkonvention? Vielleicht möchten Sie Ihre C ++ - Funktionen mit "extern C" exportieren?
Chinmay Kanchi
Ja, das habe ich getan, aber bisher kein Glück.
Neophile
6
Vielen Dank für das einfach zu befolgende Tutorial, das die Grundfunktionen von ctype zeigt
okysabeni
1
schnell und schmutzig sind immer die besten Tutorials
Lurscher
54

Die Antwort von Chinmay Kanchi ist ausgezeichnet, aber ich wollte ein Beispiel für eine Funktion, die Variablen / Arrays an einen C ++ - Code übergibt und zurückgibt. Ich dachte, ich würde es hier aufnehmen, falls es für andere nützlich ist.

Übergeben und Zurückgeben einer Ganzzahl

Der C ++ - Code für eine Funktion, die eine Ganzzahl verwendet und dem zurückgegebenen Wert eine hinzufügt.

extern "C" int add_one(int i)
{
    return i+1;
}

test.cppBeachten Sie als Datei das erforderliche externe "C" (dies kann für C-Code entfernt werden). Dies wird mit g ++ kompiliert, mit Argumenten ähnlich wie Chinmay Kanchi Antwort,

g++ -shared -o testlib.so -fPIC test.cpp

Der Python-Code verwendet load_libraryunter der numpy.ctypeslibAnnahme den Pfad zur gemeinsam genutzten Bibliothek im selben Verzeichnis wie das Python-Skript.

import numpy.ctypeslib as ctl
import ctypes

libname = 'testlib.so'
libdir = './'
lib=ctl.load_library(libname, libdir)

py_add_one = lib.add_one
py_add_one.argtypes = [ctypes.c_int]
value = 5
results = py_add_one(value)
print(results)

Dies druckt 6 wie erwartet.

Übergeben und Drucken eines Arrays

Sie können Arrays auch wie folgt übergeben, damit ein C-Code das Element eines Arrays druckt:

extern "C" void print_array(double* array, int N)
{
    for (int i=0; i<N; i++) 
        cout << i << " " << array[i] << endl;
}

die wie bisher kompiliert und auf die gleiche Weise importiert wird. Der zusätzliche Python-Code zur Verwendung dieser Funktion wäre dann:

import numpy as np

py_print_array = lib.print_array
py_print_array.argtypes = [ctl.ndpointer(np.float64, 
                                         flags='aligned, c_contiguous'), 
                           ctypes.c_int]
A = np.array([1.4,2.6,3.0], dtype=np.float64)
py_print_array(A, 3)

Dabei geben wir das Array an, das erste Argument print_arrayals Zeiger auf ein Numpy-Array ausgerichteter, c_contiguous 64-Bit-Floats und das zweite Argument als Ganzzahl, die dem C-Code die Anzahl der Elemente im Numpy-Array mitteilt. Dies wird dann durch den C-Code wie folgt gedruckt:

1.4
2.6
3.0
Ed Smith
quelle
5
Dies ist eine großartige ergänzende Antwort - schade, dass es nicht zwei angekreuzte Antworten geben kann :(
jtlz2
Ich bin mir nicht sicher, ob es zu offensichtlich ist, aber es liegt ein Fehler im Code vor. Es fehlt import numpy as np. Sonst kann es np.float64das andere Zeug nicht finden .
Ben
@ Ben, guter Ort, fügte es hinzu
Ed Smith
11

Erstens: Der >>>Code, den Sie in Python-Beispielen sehen, ist ein Weg, um anzuzeigen, dass es sich um Python-Code handelt. Es wird verwendet, um Python-Code von der Ausgabe zu trennen. So was:

>>> 4+5
9

Hier sehen wir, dass die Zeile, mit >>>der beginnt, der Python-Code ist und 9 daraus resultiert. Genau so sieht es aus, wenn Sie einen Python-Interpreter starten, weshalb dies so gemacht wird.

Sie geben das >>>Teil niemals in eine .pyDatei ein.

Das behebt Ihren Syntaxfehler.

Zweitens ist ctypes nur eine von mehreren Möglichkeiten, Python-Bibliotheken zu verpacken. Andere Möglichkeiten sind SWIG , das Ihre Python-Bibliothek überprüft und ein Python C-Erweiterungsmodul generiert, das die C-API verfügbar macht. Eine andere Möglichkeit ist die Verwendung von Cython .

Sie alle haben Vor- und Nachteile.

SWIG macht Ihre C-API nur für Python verfügbar. Das bedeutet, dass Sie keine Objekte oder ähnliches erhalten. Dazu müssen Sie eine separate Python-Datei erstellen. Es ist jedoch üblich, ein Modul namens "wowza" und ein SWIG-Modul namens "_wowza" zu haben, das den Wrapper um die C-API darstellt. Dies ist eine schöne und einfache Art, Dinge zu tun.

Cython generiert eine C-Extension-Datei. Dies hat den Vorteil, dass der gesamte von Ihnen geschriebene Python-Code in C erstellt wird, sodass sich die von Ihnen geschriebenen Objekte auch in C befinden. Dies kann eine Leistungsverbesserung darstellen. Aber Sie müssen lernen, wie es mit C zusammenarbeitet, so dass es ein bisschen mehr Arbeit ist, um zu lernen, wie man es benutzt.

ctypes haben den Vorteil, dass kein C-Code kompiliert werden muss. Daher ist es sehr hilfreich, Standardbibliotheken zu verpacken, die von einer anderen Person geschrieben wurden und bereits in Binärversionen für Windows und OS X vorhanden sind.

Lennart Regebro
quelle