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(a, b):
a.contents = b.contents
p0 = pointer(Point())
p1 = pointer(Point())
copy_point(p0,p1)
contents
がまだPythonのctypesの構造物であるように、その基準自体として管理されている。
明白な回避策は、(それはPythonのint型の不変として表現される)手動で各フィールドをコピーするだろうが、それはより複雑な構造を拡張できません。また、それは基本的でない分野が、構造化タイプのために再帰的に実行する必要があります。
Pythonは動的ににつながる、特殊タイプとサイズのオブジェクトとそれを使用するにはあまりにも簡単だろう型付けされたように、(私の他のオプションは、memmove
を使用して、彼らはバッファであるかのようにオブジェクトをコピーすることであるが、それは非常にエラーが発生しやすいと思われますメモリの破損やセグメンテーションフォールト)...
任意の提案ですか?
編集
私もそう多分これが有用である可能性があり、構造の新鮮な新しいコピーを使用することができます:
import copy
p0 = Point()
p1 = copy.deepcopy(p0) #or just a shallow copy for this example
が、それらは通常のPythonオブジェクトであるかのように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
はここに正しい動作です。あなたの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
出力:
$ 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))
しかし、まだそこよりよい選択肢があるかもしれません...
Pythonの3倍で、あなたのコードが正しく実行することができます。以下に示す:
>>> 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