2010-10-14 10 views
5

Hallo,Số tham chiếu Python và ctypes

Tôi có một số khó khăn khi hiểu số tham chiếu python. Điều tôi muốn làm là trả về một bộ tuple từ C++ sang python bằng cách sử dụng mô-đun ctypes.

C++:

PyObject* foo(...) 
{ 

    ... 
    return Py_BuildValue("(s, s)", value1, value2); 
} 

Python:

pointer = c_foo(...) # c_foo loaded with ctypes 
obj = cast(pointer, py_object).value 

Tôi đã không chắc chắn về số lượng ref của obj, vì vậy tôi cố gắng sys.getrefcount() và có 3. Tôi nghĩ rằng nó phải là 2 (các chức năng getrefcount làm cho một ref chính nó).

Bây giờ tôi không thể thực hiện Py_DECREF() trước khi trở về trong C++ vì đối tượng bị xóa. Tôi có thể giảm số lượng ref trong python không?

chỉnh sửa gì xảy ra với số lượng ref khi chức năng dàn diễn viên được gọi là? Tôi không thực sự chắc chắn từ tài liệu dưới đây. http://docs.python.org/library/ctypes.html#ctypes.cast

ctypes.cast (obj, type) Chức năng này cũng tương tự như các nhà điều hành dàn diễn viên trong C. Nó trả về một thể hiện mới của loại mà chỉ vào khối bộ nhớ giống như obj. loại phải là kiểu con trỏ và obj phải là đối tượng có thể được hiểu là con trỏ.

Trả lời

4

Trong nghiên cứu tiếp theo, tôi phát hiện ra rằng người ta có thể chỉ định kiểu trả về của hàm. http://docs.python.org/library/ctypes.html#callback-functions Điều này làm cho dàn diễn viên lỗi thời và số lượng ref không còn là vấn đề nữa.

clib = ctypes.cdll.LoadLibrary('some.so') 
c_foo = clib.c_foo 
c_foo.restype = ctypes.py_object 

Không có câu trả lời nào khác, tôi chấp nhận giải pháp mới của tôi làm câu trả lời.

4

Mã C++ của bạn có vẻ là một trình bao bọc cổ điển bằng cách sử dụng official C-API và hơi lạ vì ctypes thường được sử dụng để sử dụng kiểu c cổ điển trong python (như int, float, v.v ...).

Tôi sử dụng cá nhân C-API "một mình" (không có ctypes) nhưng trên kinh nghiệm cá nhân của tôi, bạn không phải lo lắng về bộ đếm tham chiếu trong trường hợp này kể từ khi bạn trả về kiểu gốc python với Py_BuildValue. Khi một hàm trả về một đối tượng, số quyền sở hữu của đối tượng trả về được gán cho hàm gọi.

Bạn cần phải lo lắng về Py_XINCREF/Py_XDECREF (tốt hơn so với Py_INCREF/Py_DECREF vì nó chấp nhận con trỏ NULL) chỉ khi bạn muốn thay đổi quyền sở hữu của đối tượng:

Ví dụ, bạn đã tạo một wrapper của một bản đồ trong python (hãy gọi đối tượng đã gõ py_map). Các phần tử là của c + + lớp Foo và bạn đã tạo ra một wrapper python khác cho họ (chúng ta hãy gọi nó là py_Foo). Nếu bạn tạo một chức năng mà quấn [] nhà điều hành, bạn sẽ trả về một đối tượng py_Foo trong python:

F = py_Map["key"] 

nhưng kể từ khi sở hữu được trao cho các chức năng gọi điện thoại, bạn sẽ gọi destructor khi bạn xóa F và bản đồ trong C++ chứa một con trỏ đến một objet deallocated!

Giải pháp là để viết trong C++ trong wrapper của []:

... 
PyObject* result; // My py_Foo object 
Py_XINCREF(result); // transfer the ownership 
return result; 
} 

Bạn nên hãy nhìn vào khái niệm về borrowed and owned reference trong python.Điều này là cần thiết để hiểu đúng bộ đếm tham chiếu.

+0

Nhưng bạn tạo mô-đun python-c phải không? Tôi muốn bỏ qua và với ctypes bạn chỉ có thể 'ctypes.cdll.LoadLibrary ('some.so')'. Vì vậy, việc xử lý kiểu trả về là khác nhau. Với ctypes nó là 'ctypes.py_object'. Sau đó, tôi sử dụng chức năng cast và tôi không chắc chắn cách tính ref được xử lý đúng cách. Xem chỉnh sửa của tôi. – tauran

+0

Có thực sự, có thể phức tạp hơn một chút ... Tôi đã cố gắng đọc mã nguồn của diễn viên() nhưng tôi không có đủ thời gian để investiagte đúng cách. Tôi sẽ cố gắng xem xét khi nào tôi sẽ có đủ thời gian và chỉnh sửa câu trả lời nếu tôi tìm thấy thứ gì đó chứng minh rằng ctypes có quyền sở hữu (nếu là như vậy, có lẽ bạn nên xem xét việc tạo trực tiếp đối tượng python-c để loại bỏ những vấn đề này Điều đó khá dễ dàng vì bạn đã làm việc với PyObject) – ThR37