简体   繁体   English

Cython 具有不同类型的相同类

[英]Cython same classes with different types

I have two cdef classes B and C whose methods are exactly the same.我有两个 cdef 类BC ,它们的方法完全相同 The only difference between them is the type of their attributes: one has mpz attributes, the other one int attributes.它们之间的唯一区别是它们的属性类型:一个具有mpz属性,另一个具有int属性。

My first guess was to use an abstract class A which would be overriden by B and C .我的第一个猜测是使用抽象的 class A ,它将被BC覆盖。 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?).问题是 Cython 显然不希望我覆盖属性(另外,我应该为抽象 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:我的第二个猜测是使用单个 class 与这样的融合类型:

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).但是 Cython 抱怨我使用这种类型进行操作(比如% ,即使它是为这两种类型定义的)。 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?我认为 go 的方法是使用融合类型,但我怎样才能找到解决这个问题的方法?

For reasons explained in the Cython: templates in python class wrappers this generally isn't available in Cython.由于 Cython 中解释的原因:python class 包装器中的模板通常在 Cython 中不可用。 cdef classes can't have fused members. cdef classes不能有融合成员。 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.对于这种特定情况,我想知道您是否可以通过将实现从 class 中取出到单独的cdef融合函数中来做得更好。 First define a fused class for your cdef classes首先为您的cdef classes定义一个融合的 class

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.我建议在类之间不要有任何 inheritance 关系——只要让它们实现一个(半)公共接口。

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.您显然可以将cdef_pz_or_intpz_or_int混合并匹配为 arguments (如果您需要这样做),但是它可能需要为所有组合生成有效代码。


I'm not 100% confident this will work for you - if not I'm happy to delete it.我不是 100% 相信这对你有用 - 如果不是,我很乐意删除它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM