我想模仿一片C码在Python ctypes,代码是一样的东西:

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)

作为 contents 仍然是一个Python ctypes结构的对象,这是管理作为一个参考本身。

一个明显的解决办法将是要手动副本的每个领域(即表示为不可改变的蟒蛇int的),但是,这并不比例与更复杂的结构。此外,这将需要进行递归的领域,不是基本的,但是结构化的类型。

我的其他选择是使用 memmove 和复制的对象,如果他们缓冲区,但是,似乎很容易出错(作为蟒蛇是动态型它将是太容易使用的对象的不同类型和大小,导致存损坏或分割故障)...

任何建议?

编辑:

我还可以使用一个全新的复制的结构,因此,也许这可能是有用的:

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

但我不知道,如果有可能是某种怪异行为的复制ctypes proxys,如果他们经常蟒蛇的对象...

有帮助吗?

解决方案

你可以使用的序列分配到复制指的对象(而不是分配到 p.contents, ,这会改变指数值):

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 就做的类型检查你的(这不是愚蠢的证明,但总比没有好).

例的使用,验证它不会在实际上工作;):

>>> 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 是正确的操作在这里。通过设置 argtypes 你CopyPoint功能,可以很容易地执行类型的安全。

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

产出:

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

指针的操作规则不是很存的安全。我会创建包装类别的每个结构的数据类型,你有兴趣,并让他们处理的指针的复制行动。很像你在这里做。有氧和地图的功能,这可以使用递归为语法糖。

我现在还在考虑有关定义的方法,如:

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

但也可能仍有更好的选择...

在python3倍,你的代码可以正常运行。如下所示:

>>> 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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top