Search code examples
pythonpython-3.xcythonpow

(Cython) Make the modulo argument optional in __pow__


I am trying to define some built-in arithmetic operations for a cdef class in a Cython file.

At first I tried making the __pow__ function like so:

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

But received the following error message when compiling:

This argument cannot have a default value

(The argument the error message refers to is modulo)

Removing the default value for modulo allows the file to compile properly, but forces the user to provide the third argument, which is not only strange and annoying, but it also prevents the use of the ** operator (pow would have to be used instead).

How can I implement __pow__ in Cython such that the third argument is optional?


Solution

  • You don't need to assign a default value to the third argument in __pow__: cython does that for you. When using the ** operator or pow() with only 2 arguments, the third argument is set to None. You can then explicitly check for None and return NotImplemented if you don't intend to handle the 3-argument form of pow.

    A simple example 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")
    

    And an example of its use:

    import pyximport
    pyximport.install()
    from _cclass_test import Test
    
    t = Test()
    t ** 5
    pow(t, 5)
    pow(t, 5, 3)
    

    Output:

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

    (Tested with Cython version 0.29.12)