心得:刚换工作后,连续忙了2个多月,在这两个多月里,学到的东西也是比较多的,不论从算法上,源码调试上,还是代码规范性上都有一定的提升,接下来会将这段时间接触到内容逐一记录下来。先从cpython开始吧,cpython用作代码保护或者能够提升代码运行的效率。
Cpython官网:https://cython.readthedocs.io/en/latest/index.html
中文版:https://cython.apachecn.org/#/docs/29?id=%e5%9f%ba%e6%9c%ac-setuppy
CPython是特指C语言实现的Python,就是原汁原味的Python。主要目的做python的加速,当然在编译后,相应的对代码进行了保护
创建pyx文件:
hello.pyx
import time
t0 = time.time()
for i in range(100000):
pass
print("time is {}".format(time.time()-t0))
setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize("hello.pyx")
)
命令行输入python setup.py build_ext --inplace
对hello.pyx文件进行编译
将会生成hello.的so动态库,我们调用此so动态库即可。
test.py
import hello
cpython 输出
time is 0.002833843231201172
我们用python同样输出
time is 0.005338907241821289
速度提高了一半左右,要是将大量的计算方入编译,速度会有较高的提升
Python类型list,dict,tuple,等等可被用于静态类型
变量类型定义,在pyx文件中定义好了才可以调用
cdef list foo = []
cdef dict fol = {}
cdef (double, int) bar
在函数中,如果未为参数或返回值指定类型,则假定该类型为Python对象。所以最好在入参和返回值的时候定义变量类型
hello.py 如果变量输出类型未定义则会输出None
cdef list l=[1,2,3]
def lis(int x,int y):
cdef dict c ={}
a = x + y
l.append(a)
c["lis"] = l
return c
输出:
{'lis': [1, 2, 3, 3]}
cpython中比如定义了列表,但经过编译后,没办法正常调用此列表,正确的方式是用函数去返回,用函数将列表包装再返回。
也可以使用声明类cdef,使它们成为Extension Types,它们的行为非常接近python类,但是速度更快,因为它们使用struct 内部存储属性。
from __future__ import print_function
cdef class Shrubbery:
cdef list width, height
def __init__(self, w, h):
self.width = w
self.height = h
def describe(self):
print("This shrubbery is", self.width,
"by", self.height, "cubits.")
编译后test.py
import new
res = new.Shrubbery([1,2],[])
res.describe()
##输出
This shrubbery is [1, 2] by [] cubits.
注意:将类编译到cpython中后,从外面调用编译过的类属性是拿不到的,如果想拿对应的类属性,可以编写对应的方法来获取属性。
cdef class Shrubbery:
cdef list width, height
def __init__(self, w, h):
self.width = w
self.height = h
print(self.width,"width")
print("my friends: ",my_friends())
def describe(self):
print("This shrubbery is", self.width,
"by", self.height, "cubits.")
def get_width(self):
return self.width
shr = hello.Shrubbery([1,2],[3,4])
shr.describe()
print("width",shr.get_width())
如果只有一个Cython文件要转换为已编译的扩展名,则使用filename example.pyx表示关联setup.py 如下:
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("example.pyx")
)
编译:$ python setup.py build_ext --inplace
若要自动编译多个Cython文件而不显式列出所有文件,可以使用全局模式:
setup(
ext_modules = cythonize("package/*.pyx")
)
Extension如果通过它们,也可以在对象中使用全局模式cythonize():
extensions = [Extension("*", ["*.pyx"])]
setup(
ext_modules = cythonize(extensions)
)
参考地址
from setuptools import Extension, setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize("hello.pyx")
)
# include_dirs,libraries和library_dirs,它们指定链接到外部库时在哪里可以找到.h和库文件。
# module_list 可以是多个Extension也就是多个pyx文件
ext_modules = cythonize(module_list=[
Extension(name="chello",
sources=["test.pyx"],
libraries=["hello"],
include_dirs=['c2/include'],
library_dirs=['c2/lib']
), ])
# ext_modules 要构建的 Python 扩展的列表
# packages distutils将操作的Python软件包列表, 按包分发,其他的还是元数据,其中name最好是一定要到,如果安装的话生成的文件会是指定name的名字
setup(name='chello',
version="1.1.0",
author="作者",
ext_modules=ext_modules,
description='Python Distribution Utilities',
author_email='',
url='',
packages=['distutils', 'distutils.command']
)