4

下部には 2 つのファイルがあり、1 つは実行する必要がある超最小限の python ファイルで、もう 1 つは cython ファイルです。それらをファイルとして保存すると、cython 1 に「cycode.pyx」という名前が付けられ、他のファイル (「start.py」など) を実行すると自動的にコンパイルおよび実行されます。

問題

純粋な python ファイル /.start.py を実行すると、Cython から属性エラーが発生します。

例外 AttributeError: 「'cycode.Item' オブジェクトには 'cycode.insertItem' の属性 'export' がありません」

私の経験から、これは、Python 関数またはオブジェクトが public と宣言されていない cython コード (または cpdef、readonly、def など) にアクセスしようとすることを意味します。しかし、私はこの関数に Python からアクセスするつもりはありませんでした。私が見る限り、これは起こらないはずです。cython と python を明確に分離する必要があります。Python は単純な dict を持つリストのみを取得します。

問題は、なぜそれが起こるのですか?私の目標は、それを機能させることだけではありません。これは、単純な cpdef で実行できます。しかし、なぜこれが起こったのかを理解し、最終的には、Python レルムに対して cython オブジェクトをパブリックに宣言することなく、クリーンで制御された方法で cython から python にデータを送信する方法を理解する必要があります。

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
4

1 に答える 1

2

典型的なIRC効果...質問を詳細に解決すると、数分後に解決策がポップアップします(今回はFacebookチャットを介して...)。

Python/Cython では、for ループは新しいスコープを自動的に作成せず、ループ変数は特別なものではないことを忘れていました。cdef としても宣言する必要があります。

    cdef Item item
    for item in self.content:            
        result.append(item.export())
于 2014-01-15T23:22:24.697 に答える