2015-11-30 29 views
1

假設我試圖包裝vector從Cython模塊中導出包裝的C++類

module/__init__.pxd:

from libcpp.vector cimport vector 
from libc.stdint cimport uint32_t 

cdef class MyVector: 
    cdef vector[uint32_t]* thisptr 

module/__init__.pyx:

from libc.stdint cimport uint32_t 
from libcpp.vector cimport vector 
from cython.operator cimport dereference as deref 

cdef class MyVector: 
    # the field declaration is in *.pxd 
    def __cinit__(self): 
     self.thisptr = new vector[uint32_t]() 
     self.thisptr.push_back(42) 

    def __dealloc__(self): 
     del self.thisptr 
     self.thisptr = <vector[uint32_t]*> NULL 

    def mysize(self): 
     return self.thisptr.size() 

    def myget(self): 
     return deref(self.thisptr)[0] 

module/__init__.pyxbldrun.pyxbld:

def make_ext(modname, pyxfilename): 
    from distutils.extension import Extension 
    return Extension(
     name=modname, 
     sources=[pyxfilename], 
     language='c++' 
    ) 

run.pyx:

from module cimport MyVector 

cdef main(): 
    obj = MyVector() 
    print(obj.thisptr.size()) # 1 
    print(obj.mysize()) # 1 
    print(obj.myget()) # 42 

main() 

test.py:

import pyximport 
pyximport.install() 

import run 

當我運行test.py,它具有以下回溯崩潰:

Traceback (most recent call last): 
    File "/usr/lib64/python3.4/site-packages/pyximport/pyximport.py", line 210, in load_module 
    mod = imp.load_dynamic(name, so_path) 
    File "module/__init__.pxd", line 5, in init run (/home/pastafarianist/.pyxbld/temp.linux-x86_64-3.4/pyrex/run.cpp:918) 
    cdef class MyVector: 
AttributeError: 'module' object has no attribute 'MyVector' 

如果我搬到module/__init__.pyxmodule.pyxmodule/__init__.pxdmodule.pxd相同的代碼工作。我錯過了什麼,如何修復它?

其他一些相關問題。

  1. 有沒有什麼辦法,露出一個模板包裝到用Cython代碼,這樣我可以有MyVector[uint16_t]無需再寫包裝?
  2. 我正確地爲每個與C++代碼交互的源文件添加一個pyxbld文件嗎?這是多餘的嗎? (我喜歡pyximport的便利,我不想每次都手動重新編譯代碼,而我仍然試圖讓它起作用。)
  3. 如何將module編譯爲獨立擴展? setup.py應該是什麼樣子?
  4. 在上面的代碼中,我在調用C++方法之前從未使用過deref。 Cython如何理解我的意思是->,我的意思是.

我希望能夠幫到你解決這些問題。


UPD:其實,我是包裝紙谷歌的sparsehash,我已經想通了way to do what I wanted,但它看起來像黑魔法。我仍然希望澄清一下這個錯誤是怎麼回事,以及如何正確編寫Cython包裝器。

回答

2

您的主要問題是the code in __init__.so (generated from __init__.pyx) does not get executed unless you also have __init__.py (which does not get executed in this case)。因此,您可以通過創建一個空的__init__.py文件來解決問題。這一切都感覺像一個混亂的邊緣案例。在您的原始代碼中,MyVector類永遠不會添加到模塊中,因此無法用您描述的錯誤找到它。

簡短回答您的其他問題是:

  1. 沒有 - 不幸的是建立一個模板包裝類沒有什麼好辦法。你不需要爲你在Cython中使用的任何東西構建包裝類。

  2. 我覺得這將結束是他們自己的權利相當顯著的答案,所以我跳過他們。一般來說,setup.py似乎優於pyximport,如何使用它的很好的例子在文檔中。

  3. Cython會在內部跟蹤對象的類型。當它知道它正在使用一個指針時,它會用->來代替它,否則就相當直接了,如果你說你自己不需要這樣做,那麼它就是.

+0

謝謝。我想說明的是,我想要一個更接近pythonic接口的包裝類,即使在Cython模塊中也是如此。你能提供一個簡單的Cython包裝的例子嗎?我已經在GSL之後的UPD中引用了我引用的解決方案(這也是我對「__init __。py」的解釋),但它太複雜了,而且我可能會過度設計一些東西。 – Pastafarianist

+1

它看起來不錯 - 你已經使它像一個'dict'一樣工作,我認爲它就像你可以得到的Pythonic一樣。不幸的是,Cython確實包含了獨立包裝每一個功能,這給你很長的界面,所以下一次我會說,把它切成你需要的位。我看不到其他很多東西。 – DavidW

-1

你應該考慮使用'swig'。該工具將創建您在C++和Python之間進行交互所需的所有代碼。 Link to swig website

我在一個複雜的項目中使用了swig,它工作得非常好。

無論如何,如果您不想在代碼中使用此框架,則可以使用swig創建的代碼作爲參考。

+0

我需要使用Cython的包裝類。是否有可能將SWIG包裝的類與它整合? – Pastafarianist

+0

我不明白爲什麼不。這些類將可用於常規的Python代碼。網上有很多例子。 – egur