Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cython: using imported class in a type declaration

Tags:

python

cython

I'm writing a Cython 0.23 program, and I can't figure out how to use a cdef class that I import from a different module in a type declaration. Here is a snippet that reproduces the problem.

test.py:

import pyximport
pyximport.install()

from mymodule import *

obj = MyClass(42)
print(obj.field)
print(identity(obj).field)

This works as expected and prints 42 twice:

mymodule.pyx:

cdef class MyClass:
    cdef readonly int field
    def __init__(self, field):
        self.field = field

cpdef MyClass identity(MyClass obj):
    return obj

This fails with a compiler error:

mymodule.pyx:

from utils import MyClass

cpdef MyClass identity(MyClass obj):
    return obj

utils.pyx:

cdef class MyClass:
    cdef readonly int field
    def __init__(self, field):
        self.field = field

The error:

Error compiling Cython file:
------------------------------------------------------------
...
from utils import MyClass

cpdef MyClass identity(MyClass obj):
     ^
------------------------------------------------------------

mymodule.pyx:3:6: 'MyClass' is not a type identifier

Error compiling Cython file:
------------------------------------------------------------
...
from utils import MyClass

cpdef MyClass identity(MyClass obj):
                      ^
------------------------------------------------------------

The project I need this for is small and I can refactor it so that I don't need to import the class, but this solution doesn't look very clean. Is there a better way?

like image 215
Pastafarianist Avatar asked Nov 09 '15 19:11

Pastafarianist


1 Answers

You need to use a declaration ".pxd" file and cimport. (Essentially, cimport happens at compile time, while import happens at run time so Cython can't make use of anything imported).

Create "utils.pxd":

cdef class MyClass:
    cdef readonly int field

"utils.pyx" now reads

cdef class MyClass:
  def __init__(self, field):
    self.field = field

(i.e. remove the declaration of field since it's specified in the .pxd file).

Then in mymodule.pyx

from utils cimport MyClass
# other code follows...
like image 56
DavidW Avatar answered Nov 20 '22 13:11

DavidW