Pointers Python ctypes:复制结构';内容

Pointers Python ctypes:复制结构';内容,pointers,copy,python,ctypes,Pointers,Copy,Python,Ctypes,我想用ctypes在Python中模拟一段C代码,代码如下: typedef struct { int x; int y; } point; void copy_point(point *a, point *b) { *a = *b; } 在ctypes中,无法执行以下操作: from ctypes import * class Point(Structure): _fields_ = [("x", c_int),("y", c_int)] def copy_point(

我想用ctypes在Python中模拟一段C代码,代码如下:

typedef struct {
  int x;
  int y;
} point;

void copy_point(point *a, point *b) {
  *a = *b;
}
在ctypes中,无法执行以下操作:

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)
因为
内容
仍然是一个PythoncTypes结构对象,它本身作为引用进行管理

一个明显的解决方法是手动复制每个字段(表示为不可变的python int),但这不适用于更复杂的结构。此外,对于不是基本类型,而是结构化类型的字段,需要递归地执行此操作

我的另一个选择是使用
memmove
并像复制缓冲区一样复制对象,但这似乎非常容易出错(因为Python是动态类型的,所以很容易将其用于不同类型和大小的对象,从而导致内存损坏或分段错误)

有什么建议吗

编辑

我还可以使用新的结构副本,因此这可能会很有用:

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

但我不知道是否会有一些奇怪的行为,像复制常规Python对象一样复制ctypes代理…

我现在也在考虑定义一种方法,如:

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

但可能还有更好的选择…

指针操作通常不太安全。我将为您感兴趣的每个结构数据类型创建包装器类,并让它们处理指针复制操作。就像你在这里做的一样。有lambda和map函数,您可以递归使用它们作为语法糖。

您可以使用序列赋值来复制指向的对象(而不是赋值给
p.contents
,这会更改指针值):

ctypes
将为您进行类型检查(这不是傻瓜式的,但总比什么都没有好)

使用示例,验证它是否确实有效;):


memmove
是此处的正确操作。通过设置CopyPoint函数的
argtypes
,可以轻松实施类型安全

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
输出:

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

在python 3x中,您的代码可以正确运行。如下所示:

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

大声思考的代价。。有一些元类可以作为一种很好的映射机制使用。看起来很有希望,但它只是在赋值后更改指针对象:-s print addressof(src)和addressof(dst.contents)。这些函数不应该是传递的指针,它们应该是
ctypes
结构对象。如果您想要一个类似于您的C
copy_点的函数,请执行
dst[0]=src[0]
.Hmmmm。。。我不明白为什么行为会因为执行
dst=pointer(a)而改变;dst[0]=src
指针(a)[0]=src
:-;它不应该;但是,在交互式会话中很容易出错或意外使用旧变量。不幸的是,如果ctypes结构包含指针,则
deepcopy
会失败:
ValueError:ctypes对象包含指针,无法进行pickle
$ 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
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
<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>
>>> 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