문제

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 Structure 객체입니다.

확실한 해결 방법은 각 필드(불변 Python int로 표시됨)를 수동으로 복사하는 것이지만 더 복잡한 구조에서는 확장되지 않습니다.또한 기본이 아닌 구조화된 유형의 필드에 대해서는 반복적으로 수행해야 합니다.

내 다른 옵션은 memmove 객체를 버퍼인 것처럼 복사하지만 오류가 발생하기 쉬운 것 같습니다(Python은 동적으로 유형이 지정되므로 고유한 유형과 크기의 객체와 함께 사용하기가 너무 쉬우므로 메모리 손상이나 분할 오류가 발생합니다)...

어떤 제안이 있으십니까?

편집하다:

또한 구조의 새로운 새 복사본을 사용할 수도 있으므로 이것이 유용할 수도 있습니다.

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

하지만 ctypes 프록시를 마치 일반 Python 객체인 것처럼 복사하는 일종의 기괴한 동작이 있을지는 모르겠습니다...

도움이 되었습니까?

해결책

시퀀스 할당을 사용하여 지정 대상을 복사 할 수 있습니다 (할당하지 않고 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))

그러나 여전히 더 좋은 옵션이있을 수 있습니다 ...

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top