Pointers Python ctypes:复制结构';内容
我想用ctypes在Python中模拟一段C代码,代码如下: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(
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
结构对象。如果您想要一个类似于您的Ccopy_点的函数,请执行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