异想天开

What's the true meaning of light, Could you tell me why

如何发布你的python项目

日期:2017-10-26 20:43:08
  
最后更新日期:2017-11-04 18:21:20
python作为一门包罗万象的语言,有一点美中不足的是,依赖众多,导致打包发布麻烦。搜罗一下网上常用的解决方案。

- 方案一: 用git pull项目源码,执行脚本运行pip安装依赖库
- 方案二: pyinstaller大法,一句pyinstaller yourprogram.py命令打包一个完整的执行包
- 方案三: 利用zipfile打包
- 方案四: docker发布

方案一当pull完了后,执行setup脚本,就有点听天由命了。有的公司会自己维护一个pip的镜像,从而保证pip安装成功率。方案二看起来不错,一句脚本就搞定,无奈有安装不了pyinstaller的窘态。方案四当然是最理想的部署情况。写练习demo时,可以考虑方案三和方案二。本教程以方案三为例,同时介绍使用方案三时注意的技巧。

方案三是可以支持自己写的动态库模块加载的。先来一个例子,比如写一个简单的动态库,按照惯例用hello world为例。先来一个world.cpp
[code lang="cpp"]
#include <iostream>
extern "C"
{

void SayHello()
{
std::cout << "hello world" << std::endl;
}

}
[/code]
编译:
g++ ./world.cpp -fPIC -shared -o ./world.so
再利用python的ctypes来加载该动态库,例如本例的hello.py:
[code lang="cpp"]
from ctypes import *
import os

def hello():
print "hello"
world = cdll.LoadLibrary(os.getcwd() + '/world.so')
world.SayHello()
[/code]

最后,我们再一个封装的函数,也就是该package的main entray。
[code lang="cpp"]
#!/bin/python

from zipfile import PyZipFile

import os
import hello

hello.hello()
[/code]
注意这个文件需命名为__main__.py。 我们这里的调用顺序是,__main__.py作为入口,调用了python写的模块hello.py里面的hello函数,然后又调用c++写的world.so模块。
我们来执行一个打包命名,假设package在foo目录:
[code lang="cpp"]
python -m zipfile -c foo.zip foo/
[/code]
发布的时候,我们需要把foo.zip和world.so一起发布。并且在同一目录结构下。然后我们就可以执行:
[code lang="cpp"]
python ./package.zip
[/code]
亲测有效, 打包环境redhat操作系统,python 2.7.5,测试环境ubuntu操作系统,python 2.7.12。 打包成一个zip后,foo.zip就成解释器的root,其他非python文件,则不支持这种路径(如.so文件,.txt文件)。还有一个问题,就是调试,可以将python里面的最外层代码用try...except包含进来,然后用类似/tmp/a.txt这种文件print出来调用栈信息调试。over,have fun。