Можно сделать эту работу, но я действительно не рекомендую это. Основные проблемы:
- Контейнеры C++ не могут легко хранить объекты Python (такие как memoryviews), если вы не готовы написать код оболочки подсчета ссылок (на C++)
- You can get a C pointer to the first element of a memoryview, but:
- you must ensure that a reference to the underlying object (that owns the memory) is kept, otherwise Python will free it and you'll be using accessing invalid memory.
- указатель теряет всю информацию о длине массива.
- Вы довольно ограничены в отношении компараторов, которые вы можете использовать (они должны быть выражены как функция
cdef
) - например, я написал один, который сравнивает второй элемент массива, но потребуется перекомпиляция, чтобы перейти к сравнению третьего элемент.
Поэтому мой совет - найти другой способ сделать это. Однако:
Вам нужно написать очень маленький файл C++ для typedef
типа очереди с приоритетом, который вы хотите. Это использует std::function
в качестве компаратора, и я предположил, что вы хотите сохранить long
s. Этот файл необходим, потому что поддержка шаблонов Cython довольно ограничена.
// cpp_priority_queue.hpp
#include <functional>
#include <queue>
using intp_std_func_prority_queue = std::priority_queue<long*,std::vector<long*>,std::function<bool(long*,long*)>>;
Затем вы не можете использовать оболочку libcpp.queue.priority_queue
, поставляемую с Cython. Вместо этого пишите свои, оборачивая нужные вам функции ("priority_queue_wrap.pyx")
# distutils: language = c++
from libcpp cimport bool
cdef extern from "cpp_priority_queue.hpp":
cdef cppclass intp_std_func_prority_queue:
intp_std_func_prority_queue(...) # get Cython to accept any arguments and let C++ deal with getting them right
void push(long*)
long* top()
void pop()
bool empty()
cdef bool compare_2nd_element(long* a, long* b):
# note - no protection if allocated memory isn't long enough
return a[1] < b[1]
def example_function(list _input):
# takes a list of "memoryviewable" objects
cdef intp_std_func_prority_queue queue = intp_std_func_prority_queue(compare_2nd_element) # cdef function is convertable to function pointer
cdef long[::1] list_element_mview
cdef long* queue_element
for x in _input:
#print(x)
list_element_mview = x
assert list_element_mview.shape[0] >= 2 # check we have enough elements to compare the second one
queue.push(&list_element_mview[0]) # push a pointer to the first element
while not queue.empty():
queue_element = queue.top(); queue.pop()
print(queue_element[0],queue_element[1]) # print the first two elements (we don't know that we have any more)
Затем я создал пример функции, которая просматривает список объектов, совместимых с memoryview, преобразует их в указатели и добавляет в очередь. Наконец, он проходит через очередь по порядку и печатает то, что может. Обратите внимание, что список ввода переживает очередь!
Наконец, быстрая тестовая функция Python, которая создает соответствующий список:
import priority_queue_wrap
import numpy as np
a = np.vstack([np.arange(20),np.random.randint(0,10,size=(20,))])
l = [a[:,n].copy() for n in range(a.shape[1]) ]
print(l)
priority_queue_wrap.example_function(l)
Таким образом, объекты Python + Cython + C++ — это беспорядок: я не рекомендую делать это таким образом (но вы можете попробовать!)
person
DavidW
schedule
28.01.2018
cdef
(т. е. без связанных переменных) или класс, который вы готовы написать на C++. Было бы намного сложнее использовать общий вызов Python. - person DavidW   schedule 28.01.2018MemoryView
. В любом случае, я использую CythonMemoryView
, а не Python... Я понимаю, что это все еще объект Python, но мы можем обойтись безGIL
и т. д. - person Hameer Abbasi   schedule 28.01.2018