Menu

How to convert Python to Cython inside Jupyter Notebooks?

Let’s see how to cythonize Python code inside Jupyter notebooks step by step.

In this post we will see how to:

  1. Define and time a Python Function to benchmark
  2. How to run Python using Cython in Jupyter Notebook
  3. Let’s cythonize the function

But, let’s first answer a basic question: What is the difference between CPython and Cython?

CPython is Python’s default interpreter.

What we commonly use as Python is written in the C language and i widely available. Did you know there are other version of Python as well?

  1. IronPython – Python written in C# (for .NET)
  2. Jython – Python written in Java
  3. RustPython – Written in Rust
  4. PyPy – Written in a subset of Python called RPython. Known for its speed enhancements.
  5. Brython – Written in Javascript for client side web programming.

The syntax for all these languages is common and is the same as the Python we use everyday. Interesting isn’t it?

However, unlike CPython, the Cython module converts code back into C, compiles it and we can directly call the compiled function without the need for an interpreter.

Let’s now see how to Cythonize python code in Jupyter Notebook environment.

To benchmark let’s first write a simple for-loop logic using Python code and measure how long it takes to run.

1. Define and time a Python Function to benchmark

Let’s create a simple function and measure how long it takes to execute in Python.

import time
def somefunc(K):
    accum = 0
    for i in range(K):
        if i % 5:
            accum = accum + i
    return accum

Measure the time.

t1 = time.time()
somefunc(20000000)
t2 = time.time()
t = t2-t1
print("%.10f" % t, "seconds")
3.0396461487 seconds

So, it takes about 3.03 seconds.

Let’s now see try to run the function using Cython and see if we gain some speed.

2. How to run Python using Cython in Jupyter Notebook

We can do this in 3 simple steps:

Step 1: Install the cython package.

!pip install cython
Collecting cython
  Downloading Cython-3.0.3-cp311-cp311-win_amd64.whl (2.8 MB)
                                              0.0/2.8 MB ? eta -:--:--
                                              0.0/2.8 MB 640.0 kB/s eta 0:00:05
     -                                        0.1/2.8 MB 1.0 MB/s eta 0:00:03
     --------                                 0.6/2.8 MB 4.8 MB/s eta 0:00:01
     ------------------                       1.3/2.8 MB 8.1 MB/s eta 0:00:01
     ----------------------------------       2.4/2.8 MB 10.8 MB/s eta 0:00:01
     ---------------------------------------- 2.8/2.8 MB 11.1 MB/s eta 0:00:00
Installing collected packages: cython
Successfully installed cython-3.0.3

Step 2: Load the cython extension.

%load_ext cython

For Windows: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build Tools”: https://visualstudio.microsoft.com/visual-cpp-build-tools/

Step 3: Add the Cython magin in the beginning of the cell where you want Cython to convert the Python code.

%%cython -a

def somefunc_cy(K):
    accum = 0
    for i in range(K):
        if i % 5:
            accum = accum + i
    return accum
Content of stdout:
_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6.c
   Creating library C:\Users\Akash\.ipython\cython\Users\Akash\.ipython\cython\_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6.cp311-win_amd64.lib and object C:\Users\Akash\.ipython\cython\Users\Akash\.ipython\cython\_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6.cp311-win_amd64.exp
Generating code
Finished generating code






Cython: _cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6.pyx


Generated by Cython 3.0.3

Yellow lines hint at Python interaction.
Click on a line that starts with a “+” to see the C code that Cython generated for it.

 1: 
+2: def somefunc_cy(K):
/* Python wrapper */
static PyObject *__pyx_pw_54_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6_1somefunc_cy(PyObject *__pyx_self, 
###  2.1. CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
static PyMethodDef __pyx_mdef_54_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6_1somefunc_cy = {"somefunc_cy", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_54_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6_1somefunc_cy, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_54_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6_1somefunc_cy(PyObject *__pyx_self, 
###  2.2. CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
) {
  PyObject *__pyx_v_K = 0;
###  2.3. !CYTHON_METH_FASTCALLLL
  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
  #endif
  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("somefunc_cy (wrapper)", 0);
###  2.4. !CYTHON_METH_FASTCALLLL
###  2.5. CYTHON_ASSUME_SAFE_MACROSOS
  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
  #else
  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
  #endif
  #endif
  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
  {
    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_K,0};
  PyObject* values[1] = {0};
    if (__pyx_kwds) {
      Py_ssize_t kw_args;
      switch (__pyx_nargs) {
        case  1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds);
      switch (__pyx_nargs) {
        case  0:
        if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_K)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[0]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 2, __pyx_L3_error)
        else goto __pyx_L5_argtuple_error;
      }
      if (unlikely(kw_args > 0)) {
        const Py_ssize_t kwd_pos_args = __pyx_nargs;
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "somefunc_cy") < 0)) __PYX_ERR(0, 2, __pyx_L3_error)
      }
    } else if (unlikely(__pyx_nargs != 1)) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
    }
    __pyx_v_K = values[0];
  }
  goto __pyx_L6_skip;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("somefunc_cy", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 2, __pyx_L3_error)
  __pyx_L6_skip:;
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  {
    Py_ssize_t __pyx_temp;
    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
      __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
    }
  }
  __Pyx_AddTraceback("_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6.somefunc_cy", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_54_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6_somefunc_cy(__pyx_self, __pyx_v_K);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  {
    Py_ssize_t __pyx_temp;
    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
      __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
    }
  }
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_54_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6_somefunc_cy(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_K) {
  PyObject *__pyx_v_accum = NULL;
  PyObject *__pyx_v_i = NULL;
  PyObject *__pyx_r = NULL;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_AddTraceback("_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6.somefunc_cy", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XDECREF(__pyx_v_accum);
  __Pyx_XDECREF(__pyx_v_i);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple_ = PyTuple_Pack(3, __pyx_n_s_K, __pyx_n_s_accum, __pyx_n_s_i); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple_);
  __Pyx_GIVEREF(__pyx_tuple_);
/* … */
  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_54_cython_magic_8fbc48008287a01d5af77cea06745f284b6e6aa6_1somefunc_cy, 0, __pyx_n_s_somefunc_cy, NULL, __pyx_n_s_cython_magic_8fbc48008287a01d5a, __pyx_d, ((PyObject *)__pyx_codeobj__2)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_somefunc_cy, __pyx_t_2) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+3:     accum = 0
  __Pyx_INCREF(__pyx_int_0);
  __pyx_v_accum = __pyx_int_0;
+4:     for i in range(K):
  __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_range, __pyx_v_K); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) {
    __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2);
    __pyx_t_3 = 0;
    __pyx_t_4 = NULL;
  } else {
    __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_4 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4, __pyx_L1_error)
  }
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  for (;;) {
    if (likely(!__pyx_t_4)) {
      if (likely(PyList_CheckExact(__pyx_t_2))) {
        {
          Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2);
          #if !CYTHON_ASSUME_SAFE_MACROS
          if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 4, __pyx_L1_error)
          #endif
          if (__pyx_t_3 >= __pyx_temp) break;
        }
        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(0, 4, __pyx_L1_error)
        #else
        __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_1);
        #endif
      } else {
        {
          Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2);
          #if !CYTHON_ASSUME_SAFE_MACROS
          if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 4, __pyx_L1_error)
          #endif
          if (__pyx_t_3 >= __pyx_temp) break;
        }
        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely((0 < 0))) __PYX_ERR(0, 4, __pyx_L1_error)
        #else
        __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_1);
        #endif
      }
    } else {
      __pyx_t_1 = __pyx_t_4(__pyx_t_2);
      if (unlikely(!__pyx_t_1)) {
        PyObject* exc_type = PyErr_Occurred();
        if (exc_type) {
          if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
          else __PYX_ERR(0, 4, __pyx_L1_error)
        }
        break;
      }
      __Pyx_GOTREF(__pyx_t_1);
    }
    __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_1);
    __pyx_t_1 = 0;
/* … */
  }
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+5:         if i % 5:
    __pyx_t_1 = __Pyx_PyInt_RemainderObjC(__pyx_v_i, __pyx_int_5, 5, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 5, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 5, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    if (__pyx_t_5) {
/* … */
    }
+6:             accum = accum + i
      __pyx_t_1 = PyNumber_Add(__pyx_v_accum, __pyx_v_i); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 6, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF_SET(__pyx_v_accum, __pyx_t_1);
      __pyx_t_1 = 0;
+7:     return accum
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(__pyx_v_accum);
  __pyx_r = __pyx_v_accum;
  goto __pyx_L0;

The new function is now ready to run.

Step 4: Everything is set. We can now run the code now.

Since Cython has already compiled somefunc_cy function, we don’t have to add the %%cython -a function in the cell. The somefunc_cy function can be called like any other Python function.

t1 = time.time()
somefunc_cy(20000000)
t2 = time.time()
t = t2-t1
print("%.10f" % t, "seconds")
1.7662577629 seconds

Notice here, we did absolutely no change to the original function, yet we have a ~50% drop in the code run time just by using the %%cython -a magic command.

3. Let’s cythonize the function

You can bring in further improvements in the code run time by defining the data type of the variables used.

The type of the accum variable is unsigned long long int.

Why is this so?

Integer is given because the sum of all numbers will be an integer. Unsigned because the sum will always be positive.

And long long?

Because the sum of all numbers can be very large. long long is added so as to increase the variable size to the maximum possible size that the system can allow.

%%cython -a

cpdef unsigned long long int somefunc_cy2(long int K):    
    cdef unsigned long long int accum = 0
    cdef long int i

    for i in range(K):
        if i % 5:
            accum = accum + i
    return accum
Content of stdout:
_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20.c
   Creating library C:\Users\Akash\.ipython\cython\Users\Akash\.ipython\cython\_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20.cp311-win_amd64.lib and object C:\Users\Akash\.ipython\cython\Users\Akash\.ipython\cython\_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20.cp311-win_amd64.exp
Generating code
Finished generating code






Cython: _cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20.pyx


Generated by Cython 3.0.3

Yellow lines hint at Python interaction.
Click on a line that starts with a “+” to see the C code that Cython generated for it.

 1: 
+2: cpdef unsigned long long int somefunc_cy2(long int K):
static PyObject *__pyx_pw_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_1somefunc_cy2(PyObject *__pyx_self, 
###  3.1. CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
static unsigned PY_LONG_LONG __pyx_f_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_somefunc_cy2(long __pyx_v_K, CYTHON_UNUSED int __pyx_skip_dispatch) {
  unsigned PY_LONG_LONG __pyx_v_accum;
  long __pyx_v_i;
  unsigned PY_LONG_LONG __pyx_r;
/* … */
  /* function exit code */
  __pyx_L0:;
  return __pyx_r;
}

/* Python wrapper */
static PyObject *__pyx_pw_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_1somefunc_cy2(PyObject *__pyx_self, 
###  3.2. CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
static PyMethodDef __pyx_mdef_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_1somefunc_cy2 = {"somefunc_cy2", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_1somefunc_cy2, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_1somefunc_cy2(PyObject *__pyx_self, 
###  3.3. CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
) {
  long __pyx_v_K;
###  3.4. !CYTHON_METH_FASTCALLLL
  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
  #endif
  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("somefunc_cy2 (wrapper)", 0);
###  3.5. !CYTHON_METH_FASTCALLLL
###  3.6. CYTHON_ASSUME_SAFE_MACROSOS
  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
  #else
  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
  #endif
  #endif
  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
  {
    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_K,0};
  PyObject* values[1] = {0};
    if (__pyx_kwds) {
      Py_ssize_t kw_args;
      switch (__pyx_nargs) {
        case  1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds);
      switch (__pyx_nargs) {
        case  0:
        if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_K)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[0]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 2, __pyx_L3_error)
        else goto __pyx_L5_argtuple_error;
      }
      if (unlikely(kw_args > 0)) {
        const Py_ssize_t kwd_pos_args = __pyx_nargs;
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "somefunc_cy2") < 0)) __PYX_ERR(0, 2, __pyx_L3_error)
      }
    } else if (unlikely(__pyx_nargs != 1)) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
    }
    __pyx_v_K = __Pyx_PyInt_As_long(values[0]); if (unlikely((__pyx_v_K == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 2, __pyx_L3_error)
  }
  goto __pyx_L6_skip;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("somefunc_cy2", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 2, __pyx_L3_error)
  __pyx_L6_skip:;
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  {
    Py_ssize_t __pyx_temp;
    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
      __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
    }
  }
  __Pyx_AddTraceback("_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20.somefunc_cy2", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_somefunc_cy2(__pyx_self, __pyx_v_K);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  {
    Py_ssize_t __pyx_temp;
    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
      __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
    }
  }
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_somefunc_cy2(CYTHON_UNUSED PyObject *__pyx_self, long __pyx_v_K) {
  PyObject *__pyx_r = NULL;
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = __pyx_f_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_somefunc_cy2(__pyx_v_K, 0); if (unlikely(__pyx_t_1 == ((unsigned PY_LONG_LONG)-1) && PyErr_Occurred())) __PYX_ERR(0, 2, __pyx_L1_error)
  __pyx_t_2 = __Pyx_PyInt_From_unsigned_PY_LONG_LONG(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_r = __pyx_t_2;
  __pyx_t_2 = 0;
  goto __pyx_L0;

  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_AddTraceback("_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20.somefunc_cy2", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple_ = PyTuple_Pack(1, __pyx_n_s_K); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple_);
  __Pyx_GIVEREF(__pyx_tuple_);
/* … */
  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_54_cython_magic_ce5f40fea156989a1abbf0f5aee20729e3b85c20_1somefunc_cy2, 0, __pyx_n_s_somefunc_cy2, NULL, __pyx_n_s_cython_magic_ce5f40fea156989a1a, __pyx_d, ((PyObject *)__pyx_codeobj__2)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_somefunc_cy2, __pyx_t_2) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_2) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+3:     cdef unsigned long long int accum = 0
  __pyx_v_accum = 0;
 4:     cdef long int i
 5: 
+6:     for i in range(K):
  __pyx_t_1 = __pyx_v_K;
  __pyx_t_2 = __pyx_t_1;
  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
    __pyx_v_i = __pyx_t_3;
+7:         if i % 5:
    __pyx_t_4 = (__Pyx_mod_long(__pyx_v_i, 5) != 0);
    if (__pyx_t_4) {
/* … */
    }
  }
+8:             accum = accum + i
      __pyx_v_accum = (__pyx_v_accum + __pyx_v_i);
+9:     return accum
  __pyx_r = __pyx_v_accum;
  goto __pyx_L0;

Cython has generated more C code for this. Let’s see if there is any improvement.

t1 = time.time()
somefunc_cy2(20000000)
t2 = time.time()
t = t2-t1
print("%.10f" % t, "seconds")
0.0721337795 seconds

It takes less than a 10th of a second now.

That’s the difference Cython can bring in just by making adding the magic %%cython -a in the beginning of the cell and declaring the data types.

Course Preview

Machine Learning A-Z™: Hands-On Python & R In Data Science

Free Sample Videos:

Machine Learning A-Z™: Hands-On Python & R In Data Science

Machine Learning A-Z™: Hands-On Python & R In Data Science

Machine Learning A-Z™: Hands-On Python & R In Data Science

Machine Learning A-Z™: Hands-On Python & R In Data Science

Machine Learning A-Z™: Hands-On Python & R In Data Science