Вопрос по python, copy, pointers, ctypes – Python ctypes: копирование содержимого структуры

9

Я хочу, чтобы имитировать кусок кода 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, который управляется как сама ссылка.

Очевидным обходным решением было бы вручную скопировать каждое поле (которое представлено как неизменный python int 's), но это нет масштаб с более сложными структурами. Кроме того, это должно быть сделано рекурсивно для полей, которые не являются базовыми, но структурированными типами.

Мой другой вариант заключается в использованииmemmove и копировать объекты, как если бы они были буферами, но это кажется очень подверженным ошибкам (так как Python динамически типизирован, было бы слишком легко использовать его с объектами различного типа и размера, что приведет к повреждению памяти или ошибкам сегментации) ...

Какие-либо предложения?

Редактировать:

Я также мог бы использовать новую новую копию структуры, так что, возможно, это может быть полезно:

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

но я нене знаю, может ли быть какое-то странное поведение, копирующее прокси ctypes, как если бы они были обычными объектами Python ...

к несчастьюdeepcopy не работает, если структура ctypes содержит указатели:.ValueError: ctypes objects containing pointers cannot be pickled 101

Ваш Ответ

5   ответов
0

Теперь я также думаю об определении метода, такого как:

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

Но там могут быть еще более приятные варианты ...

Несколько орфографических ошибок, но проверка безопасности типов рекомендуется. whatnick
6

memmove правильная операция здесь. Установивargtypes вашей функции CopyPoint, вы можете легко обеспечить безопасность типов.

from ctypes import *

class Point(Structure):
    _fields_ = [("x", c_int), ("y", c_int)]
    def __str__(self):
        return "" % (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 
 
 
Could not copy! argument 2: : 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

выход:

 
 
6

Вы можете использовать назначение последовательности для копирования объектов, на которые указывают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)
Возможно, что ^ _ ^ fortran
Это не должнот; Это'Довольно легко совершать ошибки или случайно использовать старые переменные в интерактивном сеансе. Miles
Хмммм ... я не могу понять, почему поведение изменилось от выполненияdst = pointer(a); dst[0] = src; вpointer(a)[0] = src : - | fortran
Эти функции неони должны быть переданы указатели, онидолжен бытьctypes структура объектов. Если вы хотите функцию, аналогичную вашему Ccopy_point, делать .dst[0] = src[0] Miles
Это выглядело многообещающе, но это просто изменяет pointee: -s print addressof (src) и addressof (dst.contents) после назначения проверить это. fortran
0

Операции с указателями, как правило, не очень безопасны для памяти. Я хотел бы создать классы-оболочки для каждого интересующего вас типа данных структуры и позволить им обрабатывать операции копирования указателя. Как и вы здесь. Существуют лямбда-функции и функции карт, которые вы можете использовать рекурсивно в качестве синтаксического сахара.

какой пустой ответ :-( fortran
Цена мысли вслух .. Есть метаклассы, которые могут быть использованы хороший механизм отображения.code.activestate.com/recipes/576666I» whatnick
0

В 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

Похожие вопросы