2014-01-15 35 views
4

底部是兩個文件,一個應該被執行的超級最小的python文件和一個cython文件。如果您將它們保存爲文件命名用Cython一個「cycode.pyx」,它會編譯並自動運行,一旦你執行的其他文件(如「start.py」)Python代碼無法找到cython函數事件,儘管它甚至不應該嘗試找到它。爲什麼?

的問題

如果您執行純python文件/.start.py,您將從Cython獲得一個屬性錯誤。

Exception AttributeError: "'cycode.Item' object has no attribute 'export'" in 'cycode.insertItem'

從我的經驗這意味着一個Python函數或對象試圖訪問未申報的公共用Cython代碼(或cpdef,只讀,高清等)。但我從來沒有打算從Python訪問這個函數。據我所知,這不應該發生。在cython和python之間應該有一個乾淨的分離。 Python只通過簡單的字典獲得列表。

問題是爲什麼會發生這種情況?我的目標不是讓它工作,這可以用簡單的cpdef來完成。但要理解爲什麼會發生這種情況,並最終以一種乾淨和受控的方式將數據從cython發送到python,而無需爲python領域聲明任何公開的cython對象。

start.py

#! /usr/bin/env python3 
    # -*- coding: utf-8 -*- 
    import pyximport; pyximport.install() 
    import cycode 
    #Register a callback function with the cython module. 
    #In this case just attempt to print the data. 
    cycode.callbacksDatabase.update.append(print) 


    #Call an insert function to create and insert a cython object. 
    #We should have nothing to do with this object, 
    #we just receive a simple list of dict(s) via the callback. 
    cycode.new1() 

cycode.pyx

# cython: language_level=3 
cdef class Block: 
    """A container class for Items""" 
    cdef list content 
    cdef void insert(self, Item item) 
    cdef list export(self)  

    def __cinit__(self):     
     self.content = [] 

    cdef void insert(self, Item item):   
     self.content.append(item)   

    cdef list export(self): 
     """The frontend should just receive simple data types to 
     vizualize them. Create export dicts of all items""" 
     cdef list result   
     result = [] 
     for item in self.content:    
      result.append(item.export()) #THIS is the problem. item.export() cannot be found. 
     return result   

cdef class Item: 
    cdef int value 
    cdef dict export(self) 
    def __cinit__(self, int value): 
     self.value = value 

    cdef dict export(self):   
     return { 
      "id" : id(self), 
      "value" : self.value, 
     } 

########API############# 
class Callbacks():  
    def __init__(self): 
     self.update = []   

    def _update(self): 
     ex = block.export() 
     for func in self.update:    
      func(ex) 

cdef void insertItem(int value):   
    cdef Item item 
    item = Item(value) #this should create a cython object, not a python one. 
    block.insert(item)    
    callbacksDatabase._update()   

def new1():  
    insertItem(1) 

#######Actual Data on module level####### 
cdef Block block 
block = Block() #this is just for the cython code. No direct access from python allowed. 
callbacksDatabase = Callbacks() #this should be accesable from python 

回答

2

典型的IRC效果......一旦你制定出詳細的問題解決彈出幾分鐘後(雖然這次通過Facebook聊天...)。

我忘了在Python/Cython中for循環不會自動創建一個新的作用域,並且循環變量沒什麼特別的。它也需要被聲明爲cdef。

cdef Item item 
    for item in self.content:    
     result.append(item.export()) 
相關問題