心得:刚换工作后,连续忙了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简介

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动态库即可。

cpython下载安装 cpython教程_python


test.py

import hello

cpython 输出
time is 0.002833843231201172

我们用python同样输出
time is 0.005338907241821289

速度提高了一半左右,要是将大量的计算方入编译,速度会有较高的提升

三、cpython中编码注意事项

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())

四、编译

1. 基本的setup.py

如果只有一个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

2. 包中的多个Cython文件

若要自动编译多个Cython文件而不显式列出所有文件,可以使用全局模式:

setup(
    ext_modules = cythonize("package/*.pyx")
)

Extension如果通过它们,也可以在对象中使用全局模式cythonize():

extensions = [Extension("*", ["*.pyx"])]

setup(
    ext_modules = cythonize(extensions)
)

3. 多个包时,setup文件编写


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']
      )