Reputation: 41
This question is related to this one, in the sense that it should be a solution to it but doesn't work, and I'm wondering why. The idea is to have the different instantiations of a template be derived classes of some abstract-y class, whose functions then just call methods on the derived class' object. However, it totally fails to work:
from libcpp.vector cimport vector
cdef class Vector:
def show(self):
print(self.v)
cdef class iVector(Vector):
cdef vector[int] v
def __init__(self, v):
for e in v:
self.v.push_back(e)
cdef class lVector(Vector):
cdef vector[long] v
def __init__(self, v):
for e in v:
self.v.push_back(e)
from distutils.core import setup, Extension
from Cython.Build import cythonize
e = Extension("foo", sources=["foo.pyx"], language="c++")
setup(ext_modules = cythonize([e]))
In [1]: import foo
In [2]: v = foo.iVector(range(5))
In [3]: v.show()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-3-ea66b5f25fed> in <module>()
----> 1 v.show()
/home/kartikv/Programs/foo.pyx in foo.Vector.show (foo.cpp:768)()
2 cdef class Vector:
3 def show(self):
----> 4 print(self.v)
5
6 cdef class iVector(Vector):
AttributeError: 'foo.iVector' object has no attribute 'v'
But it totally does...
Upvotes: 1
Views: 204
Reputation: 1314
When Cython compiles print(self.v)
, it has to decide whether to emit code for access to a Python-level or C-level attribute. Since no cdef attribute named v
is declared for the Vector class, it emits the code for Python-level access.
In the derived class, the v
attribute in the iVector
class, on the other hand, is “... stored directly in the object’s C struct.” . It is not available from Python, only from C, resulting in the error you see.
You can declare v
as public
or readonly
, which will make it visible to Python, but this will not work for more complex types (as you mention in your comment).
What you are trying to do is to implement a “virtual” attribute. This wouldn’t even work in C++: You would get a compiler error when trying to access a non-existing attribute, even if a derived class exists that has it.
In general, you can solve this by converting the attribute access to calling a cdef
method, which is “virtual”, but exactly how to do it depends on the actual problem you are trying to solve.
Upvotes: 2