Python除了有python2和python3的区别,还有具有众多的版本:
CPython
: 用C实现, 默认Python指的是CPython
JPython
: 用Java实现,在JVM里面执行IronPython
: 用C#实现Cython
: 一个Python的超级,可以绑定后调用CNumba
: 增加JIT功能,为 高性能科学计算
提供支持,支持CPU和GPU计算IPython
: 一个特殊的Python计算环境PyPy
: 用Python实现的Python版本,增加 JIT
功能
Python还有众多的绑定实现:
RubyPython
: 在Ruby中使用Python代码PyObjc
: 绑定Objective-C来在OS X平台实现GUI程序PyQt
: 绑定QT来实现GUI程序PyGTK
: 绑定GTK在Linux平台实现GUI程序Brython
: 用JavaScript实现Python VM,从而在浏览器中执行Python代码
这个笔记主要学习 用Cython来扩展Python程序
。
即时编译(Just-in-time compilation, JIT)
用于提高程序运行效率,对于Python而言,就是将字节码动态编译为机器码再执行,从而提高运行速度。
PyPy比较快的原因是具有 Tracing JIT
功能。
Pyrex
是一门用于编写Python扩展模块的语言,它的语法和Python十分接近,并且可以调用C程序,因此可以将C和Python混合代码程序编译为Python扩展模块,为Python所用。
由于语法和Python过于相似,甚至可以这样认为, Pyrex就是带有C数据类型的Python。
Cython是Pyrex的衍生
,但增加了更多特性并进行了优化。
Cython作为一个Python的编译器,在科学计算方面很流行,用于提高Python速度,通过OpenMPI库还可以进行并行计算。
hello.pyx:
# hello.pyx - Python Module, this code will be translated to C by Cython.def say_hello(): print "Hello World!"
lanuch.py:
# launch.py - Python stub loader, loads the module that was made by Cython.# This code is always interpreted, like normal Python.# It is not compiled to C.import hellohello.say_hello()
setup.py:
# setup.py - unnecessary if not redistributing the code, see belowfrom distutils.core import setupfrom Cython.Build import cythonizesetup(name = 'Hello world app', ext_modules = cythonize("*.pyx"))
编译扩展模块:
$ python setup.py build_ext --inplace$ ls -1buildhello.chello.pyxhello.solanuch.pysetup.py$ python lanuch.pyHello World!
Cython代码必须编译执行,分为两步:
.pyx
文件被Cython编译为 .c
的C语言程序将C程序编译为Python可导入使用的模块 .so(Windows平台是.pyd)
文件
Cython编译的方法有多种,但最好使用 distutils
方式:
# setup.py# run: python setup.py build_ext --inplacefrom distutils.core import setupfrom Cython.Build import cythonizesetup( name = 'Hello world app', ext_modules = cythonize("hello.pyx"),)
在Cython中可以通过标记静态类型来提高速度,凡是标记为静态类型的部分则会动态语言类型变成简单的C代码,从而提高速度。
但是如果滥用静态类型,则会降低可读性,甚至因为不当的类型设置导致错误的类型检查而导致速度降低。
Python原生代码:
def f(x): return x**2-xdef integrate_f(a, b, N): s = 0 dx = (b-a)/N for i in range(N): s += f(a+i*dx) return s * dx
Cython代码:
def f(double x): return x**2-xdef integrate_f(double a, double b, int N): cdef int i cdef double s, dx s = 0 dx = (b-a)/N for i in range(N): s += f(a+i*dx) return s * dx
在这里通过类似 cdef int
来声明静态类型,从而在将for循环编译为C代码提高速度,注意参数也增加了类型。
测试结果大概有4倍速度的提高:
$ time python test2.pyreal 0m0.888suser 0m0.809ssys 0m0.026s$ time python test3.pyreal 0m3.099suser 0m2.699ssys 0m0.206s
cdef double f(double x) except? -2: return x**2-x
from libc.math cimport sincdef double f(double x): return sin(x*x)
在编译的时候(setup.py):
from distutils.core import setupfrom distutils.extension import Extensionfrom Cython.Distutils import build_extext_modules=[ Extension("demo", ["demo.pyx"], libraries=["m"]) # Unix-like specific]setup( name = "Demos", cmdclass = {"build_ext": build_ext}, ext_modules = ext_modules)
cdef extern from "math.h": double sin(double x)cdef extern from "string.h": char* strstr(const char*, const char*)cdef extern from "string.h": char* strstr(const char *haystack, const char *needle)
.pxd文件
类似C语言中的头文件,在 .pyx文件
通过 cimport
导入使用。
A.py:
def myfunction(x, y=2): a = x-y return a + x * ydef _helper(a): return a + 1class A: def __init__(self, b=0): self.a = 3 self.b = b def foo(self, x): print x + _helper(1.0)
A.pxd:
cpdef int myfunction(int x, int y)cdef double _helper(double a)cdef class A: cdef public int a,b cpdef foo(self, double x)
则既可以通过python执行A.py,也可以通过Cython编译A.pxd,编译的时候会当做有A.pyx:
cpdef int myfunction(int x, int y): a = x-y return a + x * ycdef double _helper(double a): return a + 1cdef class A: cdef public int a,b def __init__(self, b=0): self.a = 3 self.b = b cpdef foo(self, double x): print x + _helper(1.0)
cpdef
: 对于Python可使用的函数使用cdef
: 对于C可使用的函数使用
暂时先到这里,文档冗长而无序,不好读。
作者简介:
朱春来(Leslie Zhu),金融工程师,毕业于西安电子科技大学, 喜欢历史,喜欢编程. 日常在GNU/Linux环境下进行C/C++、Python开发,对Common Lisp、Node.js、金融等感兴趣。可以通过邮箱(pythonisland@gmail.com)联系他,或者直接在他的个人主页上留言.
访问朱春来(Leslie Zhu)的个人主页(http://lesliezhu.github.com)