引言

前面的文章提到了使用 Pyarmor 来保护自己的 Python 代码,Pyarmor 通过加密源代码来保护我们的代码。但是Pyarmor 是收费的,即使是有免费许可证,但是大批量使用的话还是一笔不小的成本,在不需要许可证机制保护代码的情况下可以考虑使用 Cython 来保护我们的 Python 代码。

Cython

Cython 是一种编程语言,它是 Python 的超集,允许开发者在 Python 代码中嵌入 C 语言的特性。Cython 主要用于提高 Python 代码的执行速度,同时也可以将 Python 代码编译为 C 扩展模块,从而增加代码的保护性。

Cython 安装

Cython 的安装很简单,直接使用 pip 安装就可以,我这里使用 poetry 来安装依赖。由于 Cython 会将 Python 代码编译为本地机器码,所以在使用 Cython 进行编译时,需要使用到当前平台的编译器。由于我使用 Mac,系统已经自带了,所以这里不需要重复安装了,如果使用 Windows 系统的话需要安装 C++编译器。

poetry add cython
# or
pip install cython

示例脚本

这里先准备一个示例脚本,脚本会做一个累加计算,并且访问百度获取响应。

# cython_test.py
import time
from contextlib import contextmanager

import requests


def sum_of_squares_cython(int_list):
    n = len(int_list)
    result = 0
    for i in range(n):
        result += int_list[i] ** 2
    return result


def get_response():
    return requests.get('https://www.baidu.com').text[:100]


@contextmanager
def timer():
    t = time.time()
    yield
    print(f'运行时间为:{time.time() - t:.4f}')
# demo.py
from cython_test import get_response, sum_of_squares_cython, timer

if __name__ == '__main__':
    with timer():
        print(sum_of_squares_cython([a for a in range(1000000)]))
    print(get_response())

运行以上代码,得到以下结果:

333332833333500000
运行时间为:0.2355
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charse

编译

创建 setup.py ,执行编译指令。

# setup.py

from distutils.core import setup

from Cython.Build import cythonize

setup(
    name='test_cython_project',
    ext_modules=cythonize("cython_demo/cython_test.py", language_level=3),
)

使用以下代码编译代码:

python cython_demo/setup.py build_ext --inplace

编译完成后,可以看到文件夹内生成了对应的 c 文件和 Mac 平台的 so 文件。c 文件有一万多行,这个时候调用 so 文件就可以不再需要解释器了,运行的就是本地的机器码,会快很多。

image-20241116195905628

测试运行结果

将之前的cython_test.py删除或者改名,让 Python 无法找到它,不然 Python 会重新导入它。然后Python 就会导入对应的 so 文件, so 文件其实和 Python 模块是一样的,可以直接当做模块调用,代码都不用改。

改完名后,重新运行之前的代码:

333332833333500000
运行时间为:0.2133
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charse

从累加的时间上来看,大概比之前运行快了 0.02 秒吧,而且多次运行也很稳定,达到了加速代码运行的目的。

编译产物

而且编译产物是 so 文件,这个文件是二进制的,现在好多 Python 的依赖模块都是通过 Cython 编译的,并且在分发依赖的时候分发的就是 so 或者 pyd 文件,这样主要是为了加快 Python 原生代码的运行速度。

查看 so 文件:

image-20241116200351463

image-20241116200554595

可以发现,编译后的 so 文件的确是苹果系统的可执行文件,和 Windows 上的 pyd 文件是一样的。

Cython 模块分发

Cython 模块编译后,编译产物是二进制文件,如果要分发的话可以直接分发编译产物。这个时候用户是无法看到模块对应的源代码的,但是要注意分发的时候要将模块的依赖一起分发,防止在运行时找不到依赖。

总结

Cython 是一种强大的工具,不仅可以提高 Python 代码的性能,还能保护我们代码的知识产权。Cython 编译后的产物可以明显增加逆向工程的难度,保护我们的代码不被盗用。如果我们的需求仅仅只是保护代码,不需要许可证机制并且不需要特别强大的加密的话,可以优先使用 Cython,兼容性和性能会比 Pyarmor 更好一些。


LLLibra146
35 声望6 粉丝

会修电脑的程序员