2014-11-24 2 views
4

Мне было интересно, можно ли подклассифицировать различные типы ctypes. Я попытался написать простой пример, но есть одна (или две) вещи, которые я не понимаю.Подклассы типов типов

from ctypes import * 

class my_c_int(c_int): 
    pass 
    # def __new__(*args): 
    #  print "Hello from __new__" # why is this not called? 

libc = cdll.LoadLibrary("libc.dylib") 
printf = libc.printf 
# printf.restype = c_int # prints "14" 
printf.restype = my_c_int # prints "<my_c_int object at 0x...>" 
print printf("Hello, %s\n", "World!") 

Почему не my_c_int возвращает тот же тип, что и исходный c_int, а именно int? Можно ли это сделать? Если я пишу print printf(...).value, он работает. Можно ли автоматически вернуть .value для my_c_int?

PS: Btw., Почему метод __new__ не называется?


Edit:

Рассмотрим другой пример, из документации:

from ctypes import * 

libc = cdll.LoadLibrary("libc.dylib") 

IntArray5 = c_int * 5 
ia = IntArray5(5, 1, 7, 33, 99) 
qsort = libc.qsort 
qsort.restype = None 

CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int)) 

def py_cmp_func(a, b): 
    print "py_cmp_func", a[0], b[0] 
    return a[0] - b[0] 

cmp_func = CMPFUNC(py_cmp_func) 

qsort(ia, len(ia), sizeof(c_int), cmp_func) 

Хорошо, это работает. Мой вопрос: возможно ли изменить аргументы, получаемые функцией CMPFUNC? Можно ли это сделать, используя какой-то тип/тип подкласса типа?

Например, я хотел бы передать py_cmp_func целые числа непосредственно (а не указатели). Я могу сделать:

from ctypes import * 

libc = cdll.LoadLibrary("libc.dylib") 

IntArray5 = c_int * 5 
ia = IntArray5(5, 1, 7, 33, 99) 
qsort = libc.qsort 
qsort.restype = None 

CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int)) 

def auxiliary(a, b): 
    return py_cmp_func(a[0], b[0]) 

def py_cmp_func(a, b): 
    print "py_cmp_func", a, b 
    return a - b 

cmp_func = CMPFUNC(auxiliary) 

qsort(ia, len(ia), sizeof(c_int), cmp_func) 

Это тоже работает, но это не то, что я после. Возможно ли иметь такое поведение без функции auxiliary? Вид:

from ctypes import * 

libc = cdll.LoadLibrary("libc.dylib") 

IntArray5 = c_int * 5 
ia = IntArray5(5, 1, 7, 33, 99) 
qsort = libc.qsort 
qsort.restype = None 

class my_int_pointer(object): 

    @classmethod 
    def from_param(cls, obj): # not sure it `from_param` is the right place 
           # in any case, it will not be called, anyway... 
     return cast(obj, POINTER(c_int))[0] 

CMPFUNC = CFUNCTYPE(c_int, my_int_pointer, POINTER(c_int)) 

def py_cmp_func(a, b): 
    print "py_cmp_func", a, b[0] 
    return a - b[0] 

cmp_func = CMPFUNC(py_cmp_func) 

qsort(ia, len(ia), sizeof(c_int), cmp_func) 

но это не работает.

Короче говоря, я хотел бы знать, как настроить вход и выход функции ctypes.

+0

'__new__' в вашем примере вызывается для меня (когда не закомментирована). – 101

+0

@figs, на котором Python вы его используете? Я пробовал как CPython 2.7.5, так и PyPy 2.4.0 без успеха. –

+0

'getfunc' пропускается для подкласса. Вызов этого просто вернул бы обычный объект Python, так зачем беспокоиться? Тем не менее, методы '__new__' и' __init__' подкласса также не вызываются, поэтому вы не можете настроить результат. Он выделяет объект напрямую, вызывая тип 'tp_alloc'. Затем он копирует результат в буфер объекта. – eryksun

ответ

0

Не полный ответ, но этот код работает для меня, используя Python 2.7.6:

from ctypes import * 
class my_c_int(c_int): 
    def __new__(*args): 
     print 'new!' 
my_c_int() # prints 'new!' 
+0

Вы вызываете '__new __()' непосредственно путем вызова 'my_c_int()' (часть «()», поэтому он печатает ... –

+0

@Ecir Hana: is '__new__', который должен быть вызван перед вами создать экземпляр класса? –

+0

@PauloScardine Я так думаю. Я понимаю, что первым, кого нужно назвать, является '__new__', затем' __init__', если это то, что вы имели в виду ..? Но, может быть, я неправильно понял ваш вопрос? –

Смежные вопросы