This article is a continuation of "Introduction to Cython without Deep".
Let's get started with Cython so as not to go too deep this time. The purpose of this article is not to go into depth, but to have fun and enjoy the delicious parts of Cython.
Cython notation isn't too difficult, I've got some good sample code in the Cython tutorial, so let's borrow it.
Code before optimization
def myfunction(x, y=2):
a = x - y
return a + x * y
def _helper(a):
return a + 1
class A:
def __init__(self, b=0):
self.a = 3
self.b = b
self._scale = 2.0
self.read_only = 1.0
def foo(self, x):
return x + _helper(1.0)
If you optimize the above code with Cython, it will look like this.
Cython optimization code
%%cython
cpdef int myfunction(int x, int y=2):
cdef int a = x - y
return a + x * y
cdef double _helper(double a):
return a + 1
cdef class A:
cdef public int x
cdef public int y
cdef double _scale
cdef readonly float read_only
def __init__(self, int b=0):
self.a = 3
self.b = b
self._scale = 2.0
self.read_only = 1.0
cpdef double foo(self, double x):
return (x + _helper(1.0)) * self._scale
You can see how to type variables, arguments, and return values by looking at them, so it's not necessary to explain them.
If you look closely at the function declarations, the myfunction function is defined by cpdef
and the _helper function is defined by cdef
. The list of function declarations is as follows.
Declaration | Description |
---|---|
def | Slow, can be called from Python |
cdef | Fast, not callable from Python, only available in Cython |
cpdef | A hybrid of def and cdef, def when called from Python, cdef when called from Cython |
If you set cdef class A
in the class declaration, it becomes a cdef class.
The cdef class manages attributes with a structure compared to ordinary classes that manage attributes with a dict, so it has good memory efficiency and fast access, but it is subject to the following restrictions.
--Dynamic methods / members cannot be added --Multiple inheritance not possible with cdef method as parent, single inheritance is possible
Member definitions must be pre-defined as follows:
cdef class A:
cdef public int x
cdef public int y
cdef double _scale
cdef readonly float read_only
...
References from Python are not possible unless public is added like the _scale
member.
Also, if you add the readonly
attribute like the read_only
member, you cannot change it from Python.
a = A()
a._scale #error
a.read_only = 2.0 #error
extension | Description |
---|---|
.pyx | Think of it as an implementation file or the program itself |
.pxd | Definition file |
.pxi | Include file |
If you know the above, you will not be in trouble.
Actually, as a procedure for speeding up a Python program, it is a general procedure to add a type definition to the original program. So, let's dare to propose a different approach, that is "pure Python mode".
Let's rewrite the above sample in pure Python mode.
pure_Example rewritten in Python mode
%%cython
import cython
@cython.ccall
@cython.locals(x=cython.int, y=cython.int)
@cython.returns(cython.int)
def myfunction(x, y=2):
a = x-y
return a + x * y
@cython.cfunc
@cython.locals(a=cython.double)
@cython.returns(cython.double)
def _helper(a):
return a + 1
@cython.cclass
class A:
a = cython.declare(cython.int, visibility='public')
b = cython.declare(cython.int, visibility='public')
_scale = cython.declare(cython.double)
read_only = cython.declare(cython.double, visibility="readonly")
@cython.locals(b=cython.int)
def __init__(self, b=0):
self.a = 3
self.b = b
self._scale = 2.0
self.read_only = 1.0
@cython.ccall
@cython.locals(x=cython.double)
@cython.returns(cython.double)
def foo(self, x):
return x + _helper(1.0) * self._scale
It is a style of adding ʻimport cython` to Python code and adding type information by decorating it. Now you can run the same file in Python and compile it in Cython.
Since the type information is defined outside the function, the Python code part inside the function does not need to be changed at all. The readability of the processing part remains the same, so it's surprisingly comfortable if you get used to the decorator storm.
For details on Cython's pure Python mode, see the official documentation. It's a concise tutorial, so it's easy to read because there is almost no English text.
http://cython.readthedocs.io/en/latest/src/tutorial/pure.html
In pure Python mode, you can speed up the code in the function as it is, but you can use the .pxd file to speed up the .py file without changing it entirely.
This explanation is a brief excerpt from the official manual.
http://omake.accense.com/static/doc-ja/cython/src/tutorial/pure.html
If it finds a .pxd with the same name as the> .py file, Cython scans for cdefed classes and cdef / cpdefed functions and methods. Then convert the corresponding classes / functions / methods in the .py to the appropriate types. Therefore, if there is a.pxd like below:
cdef class A:
cpdef foo(self, int i)
At the same time, if you have a file called a.py like the one below:
class A:
def foo(self, i):
print "Big" if i > 1000 else "Small"
The code is interpreted as follows:
cdef class A:
cpdef foo(self, int i):
print "Big" if i > 1000 else "Small"
If you look closely at the code in pure Python mode, you can see [PyCharm Type Hinting](http://qiita.com/pashango2/items/de342abc10722ed7a569#%E5%BC%B7%E5%8A%9B%E3%81%AA%" E3% 82% BF% E3% 82% A4% E3% 83% 97% E3% 83% 92% E3% 83% B3% E3% 83% 86% E3% 82% A3% E3% 83% B3% E3% Similar to 82% B0). I use PyCharm type hints a lot, so I found pure Python mode easy to use.
PyCharm Type Hinting Examples
class A:
"""
:type a: int
:type b: int
"""
def __init__(self, b=0):
"""
:type b: int
"""
self.a = 3
self.b = b
def foo(self, x):
"""
:type x: float
:rtype: float
"""
return x * float(self.a)
Also, Python has a stub file (.pyi) that contains only type information.
https://www.python.org/dev/peps/pep-0484/#stub-files
The stub file is very similar to the "agumenting.pxd file" described at the end.
In the future, Python code with type hints or Python code with type annotations will be automatically accelerated by Cython without any modification of the code (although it will be difficult to completely accelerate it, of course). I'm personally happy when it comes to this.
However, I haven't found such information in my research, and if you have any information about type hints and Cython automation, please teach me.
It's pretty quick, but I introduced the features of Cython. There are many more features of Cython, but for the time being, it should be enough to speed up with Cython.
If you want to get an overview of Cython, I recommend the slides below, which are well organized.
http://www.behnel.de/cython200910/talk.html
Recommended Posts