Python-Ctypen: Kopieren des Inhaltes der Struktur

Ich möchte ein Stück C-Code in Python mit Ctypen nachahmen, der Code ist so etwas wie:

typedef struct { int x; int y; } point; void copy_point(point *a, point *b) { *a = *b; } 

In ctypes ist es nicht möglich, folgendes zu machen:

 from ctypes import * class Point(Structure): _fields_ = [("x", c_int),("y", c_int)] def copy_point(a, b): a.contents = b.contents p0 = pointer(Point()) p1 = pointer(Point()) copy_point(p0,p1) 

Da der contents noch ein Python ctypes Strukturobjekt ist, das als Referenz selbst verwaltet wird.

Ein offensichtlicher Workaround wäre, jedes Feld manuell zu kopieren (das ist als unveränderliche Python int's dargestellt), aber das skaliert nicht mit komplexeren Strukturen. Auch müsste es rekursiv für Felder geschehen, die nicht einfach sind, sondern strukturierte Typen.

Meine andere Möglichkeit ist, memmove zu verwenden und die Objekte zu kopieren, als wären sie Puffer, aber das scheint sehr fehleranfällig zu sein (da Python dynamisch typisiert ist, wäre es zu einfach, es mit Objekten unterschiedlicher Art und Größe zu verwenden, was zu Speicherbeschädigung oder Segmentierungsfehler) …

Irgendwelche Vorschläge?

Bearbeiten :

Ich könnte auch eine neue Kopie der Struktur verwenden, also vielleicht könnte das nützlich sein:

 import copy p0 = Point() p1 = copy.deepcopy(p0) #or just a shallow copy for this example 

Aber ich weiß nicht, ob es irgendeine Art von bizarren Verhaltensweisen gibt, die Ctypes Proxys kopieren, als wären sie regelmäßige Python-Objekte …

5 Solutions collect form web for “Python-Ctypen: Kopieren des Inhaltes der Struktur”

Sie können die p.contents , um die p.contents Objekte zu kopieren (anstatt den p.contents zuzuordnen, der den Zeigerwert ändert):

 def copy(dst, src): """Copies the contents of src to dst""" pointer(dst)[0] = src # alternately def new_copy(src): """Returns a new ctypes object which is a bitwise copy of an existing one""" dst = type(src)() pointer(dst)[0] = src return dst # or if using pointers def ptr_copy(dst_ptr, src_ptr): dst_ptr[0] = src_ptr[0] 

ctypes werden die Typprüfung für Sie durchführen (was nicht ctypes ist, aber es ist besser als nichts).

Beispiel der Verwendung, mit der Überprüfung, dass es tatsächlich funktioniert;):

 >>> o1 = Point(1, 1) >>> o2 = Point(2, 2) >>> print (o1.x, o1.y, addressof(o1)), (o2.x, o2.y, addressof(o2)) (1, 1, 6474004) (2, 2, 6473524) >>> copy(o2, o1) >>> pprint (o1.x, o1.y, addressof(o1)), (o2.x, o2.y, addressof(o2)) (1, 1, 6474004) (1, 1, 6473524) >>> o1 = Point(1, 1), o2 = Point(2, 2) >>> print (o1.x, o1.y, addressof(o1)), (o2.x, o2.y, addressof(o2)) (1, 1, 6473844) (2, 2, 6473684) >>> p1, p2 = pointer(o1), pointer(o2) >>> addressof(p1.contents), addressof(p2.contents) (6473844, 6473684) >>> ptr_copy(p1, p2) >>> print (o1.x, o1.y, addressof(o1)), (o2.x, o2.y, addressof(o2)) (2, 2, 6473844) (2, 2, 6473684) >>> addressof(p1.contents), addressof(p2.contents) (6473844, 6473684) 

memmove ist die richtige Bedienung hier. Durch die Einstellung der argtypes Ihrer CopyPoint-Funktion können Sie die Typsicherheit einfach erzwingen.

 from ctypes import * class Point(Structure): _fields_ = [("x", c_int), ("y", c_int)] def __str__(self): return "<Point: x=%d, y=%d, addr=%ld>" % (self.x, self.y, addressof(self)) def CopyPoint(a, b): memmove(a, b, sizeof(Point)) CopyPoint.argtypes = [POINTER(Point), POINTER(Point)] pt0 = Point(x=0, y=10) pt1 = Point(x=5, y=7) print pt0, pt1 CopyPoint(byref(pt0), byref(pt1)) print pt0, pt1 try: CopyPoint(byref(pt0), Point(x=2, y=3)) except ArgumentError as e: print "Could not copy!", e 

Ausgänge:

 $ python ct.py <Point: x=0, y=10, addr=3083711192> <Point: x=5, y=7, addr=3083711120> <Point: x=5, y=7, addr=3083711192> <Point: x=5, y=7, addr=3083711120> Could not copy! argument 2: <type 'exceptions.TypeError'>: wrong type 

Beachten Sie, dass Sie leicht eine Fabrik erstellen können, um diese Art von Funktion zur Laufzeit basierend auf einem bestimmten Typ zu generieren, wenn Sie verallgemeinern müssen:

 def CopierFactory(typ): def f(a,b): memmove(a,b, sizeof(typ)) f.argtypes = [POINTER(typ), POINTER(typ)] return f copy_point = CopierFactory(Point) a = Point(x=1, y=2) b = Point(x=-1, y=-1) print a, b copy_point(byref(a), byref(b)) print a, b 

Ausgabe:

 <Point: x=1, y=2, addr=3085088024> <Point: x=-1, y=-1, addr=3085087952> <Point: x=-1, y=-1, addr=3085088024> <Point: x=-1, y=-1, addr=3085087952> 

Zeigeroperationen als Regel sind nicht sehr speicher sicher. Ich würde Wrapper-Klassen für jeden Struktur-Datentyp erstellen, an dem Sie interessiert sind, und lassen Sie sie mit den Zeiger-Kopieroperationen umgehen. So gut wie du hier machst Es gibt Lambda- und Kartenfunktionen, die man rekursiv als syntaktischen Zucker verwenden kann.

Ich denke jetzt auch über die Definition einer Methode wie:

 def safe_copy(dst, src): if type(src) != type(dst) or not isinstance(src, Structure): raise Exception("wrong types") memmove(addressof(dst), addressof(src), sizeof(src)) 

Aber vielleicht gibt es noch schönere Optionen da draußen …

In python 3x kann dein Code korrekt laufen. Unten gezeigt:

 >>> from ctypes import * >>> class Point(Structure): ... _fields_ = [("x", c_int),("y", c_int)] >>> def copy_point(a, b): ... a.contents = b.contents >>> p0 = pointer(Point()) >>> p1 = pointer(Point(1,2)) >>> p0.contents.x 0 >>> copy_point(p0,p1) >>> p0.contents.x 1 
  • Interpretieren Sie die Liste der Ganzzahlen als Float in Python
  • Python-Ctypes, die in Zeiger übergeben und Struct Back erhalten
  • Zugriff auf die zugrunde liegende Struktur eines PyObjects
  • Liste vs. int Zuweisung - "Jede Variable ist ein Zeiger"
  • Python ist die beste Programmiersprache der Welt.