【问题标题】:Cython same classes with different typesCython 具有不同类型的相同类
【发布时间】:2020-04-11 22:44:01
【问题描述】:

我有两个 cdef 类 BC,它们的方法完全相同相同。它们之间的唯一区别是它们的属性类型:一个有mpz 属性,另一个有int 属性。

我的第一个猜测是使用抽象类A,它会被BC 覆盖。问题是 Cython 显然不希望我覆盖属性(另外,我应该为抽象类的属性赋予哪种类型?)。我这样做的错误是:

------------------------------------------------------------
...

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

我的第二个猜测是像这样使用具有融合类型的单个类:

ctypedef fused mpz_or_int:
    int
    mpz

但是 Cython 抱怨我使用这种类型进行操作(例如 %,即使它是为这两种类型定义的)。我得到的错误是:

------------------------------------------------------------
...
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

现在,我复制/粘贴了这两个类,但这是一个肮脏的 hack,显然,每次我必须修改这些类的方法时,我都哭了 :)

我认为要走的路是使用融合类型,但我怎样才能找到解决这个问题的方法呢?

【问题讨论】:

  • 这是一个非常相似的问题stackoverflow.com/questions/31436593/…。不幸的是,我认为没有出现任何新的解决方案。基本上你可能确实需要复制和粘贴,但你可以尝试自动化
  • 该死的,希望有一个更漂亮的解决方案:'(不过还是谢谢!
  • 肯定会很好。我确实有另一个想法可能适用于您的具体情况......
  • 真的吗?解决方法是什么,或者至少是原则,所以我也可以考虑一下?
  • 我已通过建议发布作为答案。它非常模糊且不完整,但我认为它应该可以帮助您避免一些代码重复。如果它不起作用,那么告诉我,我会摆脱它(以免误导其他人)

标签: python cython gmpy


【解决方案1】:

由于Cython: templates in python class wrappers 中解释的原因,这通常在 Cython 中不可用。 cdef classes 不能有融合成员。在回答该问题时,我建议使用“复制/粘贴”方法,但可能会尝试将其自动化。

对于这种特定情况,我想知道您是否可以通过将实现从类中取出到单独的 cdef 融合函数中来做得更好。首先为你的cdef classes定义一个融合类

ctypedef fused cdef_pz_or_int:
    # cdef classes _can_ be part of fused types
    TestModularNumber
    TestInheritance

我建议类之间不要有任何继承关系——只要让它们实现一个(半)通用接口即可。

实际的实现是在非成员融合函数中:

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....

您显然可以混合和匹配 cdef_pz_or_intpz_or_int 作为参数(如果您需要这样做),但它可能需要为所有组合生成有效代码。


我不是 100% 相信这对你有用 - 如果不是,我很乐意删除它。

【讨论】:

  • 只是为了确定(我在 Cython 中很新):如果这个方法有效,那么我会有工作功能,但这些功能不能作为方法访问,对吧?另外,大多数类代码(实际上除了平方根方法之外的所有代码)都是处理__add__ 等运算符的魔术函数。因此,我真的可以使用这种方法吗?还是我误会了?
  • 我认为你理解正确。取决于函数的内容有多大,它可能仍然值得 - 你可以定义def __add__(self, other): return add_function(self, other)。如果add_function 中有很多代码,那就值得了。如果不是,那就不是。听起来它可能不适合你
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 1970-01-01
  • 2021-05-25
  • 1970-01-01
  • 2019-12-18
  • 1970-01-01
  • 2021-07-24
相关资源
最近更新 更多