Frage

Ich mag ein Stück C-Code in Python mit ctypes imitieren, 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, die Folgendes zu tun:

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)

als die contents noch ein Objekt Python ctypes Struktur ist, dass als Referenz verwaltet selbst.

Eine offensichtliche Abhilfe wäre manuell jedes Feld kopieren (das wird als unveränderlich Python int ist dargestellt), aber das bedeutet nicht mit komplexeren Strukturen skalieren. Auch sie müssten rekursiv für Felder durchgeführt werden, die nicht basisch sind, sondern strukturierte Typen.

Meine andere Option ist memmove zu verwenden und die Objekte zu kopieren, als ob sie Puffer waren, aber das scheint sehr fehleranfällig (wie Python dynamisch typisierten wäre es zu einfach, es mit Objekten unterschiedlicher Art und Größe zu verwenden, was zu Speicherfehler oder Zugriffsfehler) ...

Irgendwelche Vorschläge?

Bearbeiten :

ich auch eine frische neue Kopie der Struktur verwenden könnte, vielleicht könnte dies 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 vielleicht eine Art bizarre Verhaltensweisen Kopieren ctypes proxys sein, als ob sie regelmäßigen Python-Objekte waren ...

War es hilfreich?

Lösung

Sie können die Sequenzzuordnung verwenden die Spitz auf Objekte zu kopieren (anstatt die Zuordnung p.contents, die 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 tun Art für Sie überprüft (das ist nicht-narrensicher, aber es ist besser als nichts).

Anwendungsbeispiel, mit Überprüfung, dass es in der Tat Arbeit;):

>>> 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)

Andere Tipps

memmove ist die korrekte Funktion hier. Durch die Einstellung des argtypes Ihrer CopyPoint Funktion können Sie leicht Typsicherheit 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 machen könnten diese Art der Funktion zur Laufzeit zu erzeugen, basierend auf einem bestimmten Typ, 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>

Pointer-Operationen in der Regel nicht sehr Speicher sicher. Ich würde Sie Wrapper-Klassen für jede Struktur-Datentyp erstellen interessiert sind, und lassen Sie sie die Zeigerkopiervorgänge behandeln. Ziemlich genau wie machst du hier. Es gibt Lambda und Kartenfunktionen, die Sie rekursiv als syntaktischer Zucker verwenden können.

Ich bin jetzt denken, auch eine Methode, wie etwa die Definition:

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 es könnte noch schöner Optionen da draußen ...

In Python 3x, kann Ihr Code ordnungsgemäß ausgeführt. unten dargestellt:

>>> 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top