(Cython) 在 __pow__ 中使取模参数可选

(Cython) Make the modulo argument optional in __pow__

我正在尝试为 Cython 文件中的 cdef class 定义一些内置算术运算。

起初我尝试像这样制作 __pow__ 函数:

def __pow__(self, other, modulo=None):
    pass

但是编译时收到如下错误信息:

This argument cannot have a default value

(错误信息所指的参数是modulo

删除 modulo 的默认值允许文件正确编译,但强制用户提供第三个参数,这不仅奇怪和烦人,而且还阻止了 ** 运算符(必须改用 pow)。

如何在 Cython 中实现 __pow__ 以便第三个参数是可选的?

您可以使用装饰器来欺骗 cython 编译器认为该参数没有默认值:

def trickster(func):
    def wrapper(self, other, modulo=None):
        return func(self, other, modulo)
    return wrapper


class MyClass:
   ...
   @trickster
   def __pow__(self, other, modulo):
       ...

您不需要为 __pow__ 中的第三个参数分配默认值:cython 会为您完成。当使用只有 2 个参数的 ** 运算符或 pow() 时,第三个参数设置为 None。如果您不打算处理 pow.

的 3 参数形式,则可以显式检查 Nonereturn NotImplemented

一个简单的例子cython class, in _cclass_test.pyx:

# cython: language_level=3
cdef class Test:
    def __pow__(x, y, z):
        if z is None:
            print("Called with just x and y")
        else:
            print("Called with x, y and z")

及其使用示例:

import pyximport
pyximport.install()
from _cclass_test import Test

t = Test()
t ** 5
pow(t, 5)
pow(t, 5, 3)

输出:

$ python cclass_test.py 
Called with just x and y
Called with just x and y
Called with x, y and z

(使用 Cython 版本 0.29.12 测试)