I have two cdef classes B
and C
whose methods are exactly the same. The only difference between them is the type of their attributes: one has mpz
attributes, the other one int
attributes.
My first guess was to use an abstract class A
which would be overriden by B
and C
. The problem is that Cython apparently doesn't want me to override attributes (plus, which type should I give to the attribute of the abstract class?). The error I got by doing this was:
------------------------------------------------------------
...
cdef class TestModularNumber:
cdef readonly mpz value, modulo
cdef class TestInheritance(TestModularNumber):
cdef readonly int value, modulo ^
------------------------------------------------------------
finite_field/testmodular.pxd:10:22: 'value' redeclared
My second guess was to use a single class with fused type like this:
ctypedef fused mpz_or_int:
int
mpz
But Cython complains about the fact that I do operations with this type (like %
, even though it is defined for both of the types). The errors I got are:
------------------------------------------------------------
...
ctypedef fused mpz_or_int:
int
mpz
cdef class TestModularNumber:
cdef readonly mpz_or_int value, modulo ^
------------------------------------------------------------
finite_field/testmodular.pxd:12:36: Type is not specialized
------------------------------------------------------------
...
from gmpy2 import invert, powmod
cdef class TestModularNumber:
def __cinit__(self, mpz_or_int value, mpz_or_int modulo):
self.value = value
^
------------------------------------------------------------
finite_field/testmodular.pyx:7:12: Invalid use of fused types, type cannot be specialized
------------------------------------------------------------
...
if not self.has_modular_square_root():
raise ValueError(f"{self.value} is a non-residue modulo {self.modulo}.")
if self.value == 0 or self.value == 1:
return TestModularNumber(self.value, self.modulo)
if self.modulo % 4 == 3:
^
------------------------------------------------------------
finite_field/testmodular.pyx:145:23: Compiler crash in AnalyseExpressionsTransform
For now, I copy/pasted the two classes, but that's a dirty hack, and obviously, every time that I have to modify a method of these classes, I cry:)
I think the way to go is using fused types, but how can I find a workaround to this problem?
For reasons explained in the Cython: templates in python class wrappers this generally isn't available in Cython. cdef classes
can't have fused members. In the answer to that question I proposed using the "copy/paste" method, but maybe trying to automate it.
For this specific case I wonder if you could do a bit better by taking the implementation out of the class into separate cdef
fused functions. First define a fused class for your cdef classes
ctypedef fused cdef_pz_or_int:
# cdef classes _can_ be part of fused types
TestModularNumber
TestInheritance
I'd recommend not having any inheritance relationship between the classes - just have them implement a (semi-)common interface.
The actual implementation is then in non-member fused functions:
cdef has_modular_square_root(cdef_pz_or_int self):
value = self.value # cython should be able to infer this type
# more logic goes here....
You could obviously mix and match cdef_pz_or_int
and pz_or_int
as arguments (if you need to do so) however it'd probably need to generate valid code for all combinations.
I'm not 100% confident this will work for you - if not I'm happy to delete it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.