Xronx
Xronx

Reputation: 1220

Correct way to init object in cython function

I'm using following cython code:

cimport numpy as np
np.import_array()


cdef class Seen:
    cdef bint sint_

    def __cinit__(self):
        print('INIT seen object')
        self.sint_ = 0

    cdef saw_int(self, object val):
        self.sint_ = 1


def test(object val):
    test_type(val)


def test_type(object val, Seen seen=Seen()):
    print ('BEFORE:', seen.sint_)
    val = int(val)
    seen.saw_int(val)
    print ('AFTER:', seen.sint_)

Build it and call functions like so:

import test
import numpy as np

test.test(-1)
print('')
test.test(np.iinfo(np.uint64).max)

The output which produces questions:

INIT seen object
BEFORE: False
AFTER: True

BEFORE: True
AFTER: True


As output states - seen object is not instantiated in second test.test call. But at the same time if change test_type declaration like so:

cdef test_type(object val):
    cdef  Seen seen=Seen()
    ...

Init happens on each call.

So 2 questions:

  1. Why 2 realizations of test_type is different? As far as I remember from cython docs these two is interchangable.
  2. How should I pass seen object to the test_type with the default as init new one? If (..., Seen seen=Seen()) not working?

Upvotes: 0

Views: 244

Answers (1)

chepner
chepner

Reputation: 532003

The default value of a function is evaluated once, when the function is defined. If you want a new Seen instance each time you call test_type, do the following:

def test_type(object val, Seen seen=None):
    if seen is None:
        seen = Seen()
    print ('BEFORE:', seen.sint_)
    val = int(val)
    seen.saw_int(val)
    print ('AFTER:', seen.sint_)

Caveat: I'm not very familiar with cython, so there might be a subtlety that I am missing. But this would be the issue in ordinary Python code, and I suspect the same issue applies here.

Upvotes: 1

Related Questions