Sia
Sia

Reputation: 207

Share declaration of cython's extension type which is a member data of another extension type

I want to share the declaration of one class which is the member data of another class in cython using the share of declaration for extension types.

Example of code:

This is the python wrapper (run.py) that is run by user. It declares a Solver class.

#! /usr/bin/env python
# filename: run.py 

import Solver

S = Solver.Solver()
Result = S.Solve()

The Solver object has a cpdef Solve() member function which is called once from the python part of the code. The Solver class has cdef object Computation member data:

# filename: Solver.pyx

from Computation cimport Computation
cdef class Solver:
    cdef object Comp

    def __cinit__(self):
        self.Comp = Computation()

    cpdef double Solve(self):
        Result =  self.Comp.Add(4)
        return Result

The Computation class is merely a cython code:

# filename: Computation.pxd

cdef class Computation:
    cdef int a
    cdef double Add(self,double b)

and

# filename: Computation.pyx

cdef class Computation:
    def __cinit__(self):
        self.a = 3

    cdef double Add(self,double b):
        return self.a + b

The setup.py is:

# filename: setup.py

from distutils.core import setup
from Cython.Build import cythonize

setup(
        package_data = {"Computation": ["Computation.pxd"]},
        ext_modules = cythonize(["*.pyx"],include_path=["."]),
)

Solver.Solve() calls Computation.Add() many times, but here I suppressed the for loops for simplicity. The point is that calling Add() should have the minimal cost, hence I have declared it with cdef.

The problem:

All files are in the same directory. I compile with python setup build_ext --inplace. Then by running ./run I receive the following error:

Exception AttributeError: "'Computation.Computation' object has no attribute 'Add'" in 'Solver.Solver.Solve' ignored

I have two ways to get around with this:

  1. If I change Add() from a cdef to a cpdef function I no longer get this error. But in this case, the Solve() calls a cpdef which has an overhead compared to cdef. I want to avoid using cpdef for Add(), since in the actual code, Add() is an expensive code and is called may times.
  2. If in the Solver class, I do not declare Comp object as a member data, rather just declare it inside the Solve() function, I do not get this error. Something like this:

    # filename: Solver.pyx
    
    from Computation cimport Computation
    cdef class Solver:
        # No member data here.
        cpdef double Solve(self):
            # We declare Comp here instead:
            Comp = Computation()
            Result =  Comp.Add(4)
            return Result
    

But I prefer the Comp to be a member of Solver as well. My guess is that by declaring Comp in a python code def __cinit__(self), the cdef functions are not declared anymore.

So, my question is that how can I share declaration of an extension type which itself is a member data of another class? That is, how a cython extension type can be declared in __cinit__()?

Upvotes: 1

Views: 345

Answers (1)

Sia
Sia

Reputation: 207

Found it myself. Simply in Solver.pyx the line

cdef object Comp

should be changed to

cdef Computation Comp

which here the object is explicitly typed. With this the extension type's cdef method can be accessed elsewhere.

Upvotes: 1

Related Questions