2010-03-18 31 views
10

Chức năng C myfunc hoạt động trên một đoạn dữ liệu lớn hơn. Các kết quả được trả về trong khối đến một chức năng gọi lại:Các đối tượng Python dưới dạng userdata trong các chức năng gọi lại của ctypes

int myfunc(const char *data, int (*callback)(char *result, void *userdata), void *userdata); 

Sử dụng ctypes, nó không có gì to tát để gọi myfunc từ mã Python, và để có kết quả được trả lại cho một hàm Python gọi lại. Điều này làm việc gọi lại tốt.

myfunc = mylib.myfunc 
myfunc.restype = c_int 
myfuncFUNCTYPE = CFUNCTYPE(STRING, c_void_p) 
myfunc.argtypes = [POINTER(c_char), callbackFUNCTYPE, c_void_p] 

def mycb(result, userdata): 
    print result 
    return True 

input="A large chunk of data." 
myfunc(input, myfuncFUNCTYPE(mycb), 0) 

Nhưng, có cách nào để cung cấp cho đối tượng Python (danh sách) làm userdata cho hàm gọi lại không? Để lưu trữ đi các khối kết quả, tôi muốn làm ví dụ:

def mycb(result, userdata): 
    userdata.append(result) 

userdata=[] 

Nhưng tôi không có ý tưởng làm thế nào để đúc danh sách Python để một c_void_p, vì vậy nó có thể được sử dụng trong các cuộc gọi đến MyFunc .

Giải pháp hiện tại của tôi là triển khai danh sách được liên kết dưới dạng cấu trúc ctypes, điều này khá cồng kềnh.

Trả lời

3

Tôi đoán bạn có thể sử dụng Python C API để làm điều đó ... có thể bạn có thể sử dụng một con trỏ PyObject.

chỉnh sửa: Khi op chỉ ra trong các ý kiến, có đã là một loại py_object sẵn trong ctypes, vì vậy giải pháp là tạo ra đầu tiên một đối tượng ctypes.py_object từ danh sách python và sau đó đúc nó để c_void_p để vượt qua nó như một đối số cho hàm C (tôi nghĩ rằng bước này có thể là không cần thiết vì tham số được nhập là void* nên chấp nhận bất kỳ con trỏ nào và sẽ nhanh hơn để vượt qua chỉ là một byref). Trong gọi lại, các bước ngược lại được thực hiện (truyền từ con trỏ void đến con trỏ tới py_object và sau đó nhận được giá trị của nội dung).

Một cách giải quyết có thể được sử dụng một kết thúc cho hàm callback của bạn để nó đã biết, trong đó liệt kê nó phải nối thêm các mục ...

myfunc = mylib.myfunc 
myfunc.restype = c_int 
myfuncFUNCTYPE = CFUNCTYPE(STRING) 
myfunc.argtypes = [POINTER(c_char), callbackFUNCTYPE] 


def mycb(result, userdata): 
    userdata.append(result) 

input="A large chunk of data." 
userdata = [] 
myfunc(input, myfuncFUNCTYPE(lambda x: mycb(x, userdata))) 
+0

Vâng, điều tốt đẹp về ctypes là mọi thứ đều có thể được thực hiện bằng Python đơn giản. Vì vậy, Python C API có vẻ là một bước trở lại. Hay tôi đang thiếu một cái gì đó? – flight

+0

Tôi có nghĩa là tùy chọn có thể tạo proxy ctypes của cấu trúc C-API PyObject, đó phải là biểu diễn bên trong của bất kỳ đối tượng Python nào và chuyển nó xung quanh ... – fortran

+0

Lạ. Cách giải quyết của bạn với một đóng cửa hoạt động tốt trên Linux, nhưng cùng một chương trình bị treo trên Windows. – flight

Các vấn đề liên quan