第十八章 程序打包
Setuptools和較舊的Distutils都是用于發布Python包的工具包,能夠使用Python輕松地編寫安裝腳本。這些腳本可用于生成可發布的歸檔文檔,供用戶用來編譯和安裝編寫庫。
Setuptools并非只能用于創建基于腳本的Python安裝程序,還可用于編譯擴展。
通過將其與擴展py2exe和py2app結合起來使用,還可創建獨立的Windows和macOS可執行程序。
Setuptools基礎
如果沒有安裝Setuptools,可使用pip安裝
簡單的Setuptools安裝腳本(setup.py)
請將代碼所示的腳本存儲為setup.py(這適用于所有的Setuptools安裝腳本),并確保其所在目錄包含簡單模塊beyond.py。
from setuptools import setupsetup(name='Beyond',version='1.0',description='A simple example',author='beyondyanyu',py_modules=['beyond'])
使用這個簡單的腳本
python setup.py
將出現類似于下面的輸出:
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]or: setup.py --help [cmd1 cmd2 ...]or: setup.py --help-commandsor: setup.py cmd --helperror: no commands supplied
要獲得更多的信息,可使用開關--help
或--help-commands
。
執行命令build,讓Setuptools行動起來。
python setup.py build
將出現類似于下面的輸出:
running build
running build_py
creating build
creating build/lib
copying beyond.py -> build/lib
Setuptools創建了一個名為build的目錄,其中包含子目錄lib。同時將將beyond.py復制到了這個子目錄中。目錄build相當于工作區,Setuptools在其中組裝包(以及編譯擴展庫等)。安裝時不需要執行命令build,因為當你執行命令install時,如果需要,命令build會自動運行。
在上述這個示例中,命令install將把模塊beyond.py復制到PYTHONPATH指定的特定目錄中。這應該不會帶來風險,但如果你不想弄亂系統,應該將其刪除。
安裝install這個模塊
python setup.py install
輸出應該非常多,其末尾的內容類似于下面這樣:
Installed /path/to/python3.5/site-packages/Beyond-1.0-py3.5.egg
Processing dependencies for Beyond==1.0
Finished processing dependencies for Beyond==1.0 byte-compiling
在安裝過程中,Setuptools創建了一個.egg文件,這是一個獨立的Python包。
在這個腳本中,只使用了Setuptools指令py_modules。如果要安裝整個包,可以類似的方式(列出包名)使用指令packages。
打包
編寫讓用戶能夠安裝模塊的腳本setup.py后,就可使用它來創建歸檔文件了。
這里主要介紹如何創建.tar.gz
文件
要創建源代碼歸檔文件,可使用命令sdist(表示source distribution)。
python setup.py sdist
如果執行上述命令,可能出現大量的輸出,其中包括一些警告。完全可以對這些警告置若罔聞,但也可在腳本setup.py中添加author_email(類似于選項author),并在當前目錄中添加文本文件README.txt。
現在,除目錄build外,應該還有一個名為dist的目錄。在這個目錄中,有一個名為Beyond-1.0.tar.gz
的文件。
可將其分發給他人,而對方可將其解壓縮,再使用腳本setup.py進行安裝。
不想生成.tar.gz
文件,還有其他幾種分發格式可供使用。要設置分發格式,可使用命令行開關--formats
(這個開關為復數形式,表明你可指定多種用逗號分隔的格式,這樣將一次性創建多個歸檔文件)。要獲悉可使用的格式列表,可給命令sdist指定開關--help-formats
。
編譯擴展
假設這個源代碼文件(palindrome2.c)位于當前目錄中(第17章中程序palindrome的源代碼),則可使用下面的setup.py腳本來編譯(并安裝)它:
一個回文檢查示例(palindrome2.c)
#include <Python.h>static PyObject *is_palindrome(PyObject *self, PyObject *args) {int i, n;const char *text;int result;if (!PyArg_ParseTuple(args, "s", &text)) {return NULL;}n=strlen(text);result = 1;for (i = 0; i <= n/2; ++i) {if (text[i] != text[n-i-1]) {result = 0;break;}}return Py_BuildValue("i", result); /* "i"表示一個整數:*/}static PyMethodDef PalindromeMethods[] = {/* 方法/函數列表:*/{"is_palindrome", is_palindrome, METH_VARARGS, "Detect palindromes"},{NULL, NULL, 0, NULL}
};static struct PyModuleDef palindrome =
{PyModuleDef_HEAD_INIT,"palindrome", /* 模塊名 */"", /* 文檔字符串 */-1, /*存儲在全局變量中的信號狀態 */PalindromeMethods
};/* 初始化模塊的函數:*/
PyMODINIT_FUNC PyInit_palindrome(void)
{return PyModule_Create(&palindrome);
}
setup.py腳本
from setuptools import setup, Extensionsetup(name='palindrome',version='1.0',ext_modules = [Extension('palindrome', ['palindrome2.c'])] )
如果使用這個腳本運行命令install,將自動編譯擴展模塊palindrome再安裝它。
這里沒有指定一個模塊名列表,而是將參數ext_modules設置為一個Extension實例列表。構造函數Extension將一個名稱和一個相關文件列表作為參數;
如果只想就地編譯擴展(在大多數UNIX系統中,這都將在當前目錄中生成一個名為palindrome.so的文件),可使用如下命令:
python setup.py build_ext --inplace
如果安裝了SWIG(參見第17章),可讓Setuptools直接使用它!
代碼palindrome.c的源代碼,顯然比包裝后的版本簡單得多。能夠讓Setuptools使用SWIG并直接將其作為Python擴展確實非常方便。
為此,需要做的非常簡單,只需將接口文件(.i文件,palindrome.i)的名稱加入到Extension實例的文件列表中即可。
palindrome.c的源代碼
#include <string.h>
int is_palindrome(char *text) {int i, n=strlen(text);for (i = 0; I <= n/2; ++i) {if (text[i] != text[n-i-1]) return 0;}return 1;
}
接口文件(palindrome.i)
%module palindrome%{
#include <string.h>
%}extern int is_palindrome(char *text);
Extension實例的文件列表
from setuptools import setup, Extensionsetup(name='palindrome',version='1.0',ext_modules = [Extension('_palindrome', ['palindrome.c','palindrome.i'])])
如果用剛才的命令(build_ext,可能還要加上開關–inplace)運行這個腳本,也將生成一個.so文件(或與之等價的文件),但這次無需自己編寫包裝代碼。
這個擴展指定了名稱_palindrome
,因為SWIG將創建一個名為palindrom.py
的包裝器,而這個包裝器將通過名稱_palindrome
導入一個C語言庫。
使用py2exe創建可執行程序
py2exe是Setuptools的一個擴展(可通過pip來安裝它),能夠創建可執行的Windows程序(.exe文件)。
py2exe包可用來創建帶GUI(參見第12章)的可執行文件。
print('Hello, world!')
input('Press <enter>')
創建一個空目錄,再將這個文件(hello.py)放到這個目錄中,然后創建一個類似于下面的setup.py文件:
beyond.py
from setuptools import setupsetup(name='Beyond',version='1.0',description='A simple example',author='beyondyanyu',py_modules=['beyond'])
setup.py
from distutils.core import setup
import py2exesetup(console=['beyond.py'])
接著運行這個腳本:
python setup.py py2exe
這將創建一個控制臺應用程序(beyond.exe),還將在子目錄dist中創建其他幾個文件。
有關py2exe的工作原理和高級用法的詳細信息,可以查閱py2exe官網。
小結
概念 | 解釋 |
---|---|
Setuptools | Setuptools工具包讓你能夠編寫安裝腳本。根據約定,這種安裝腳本被命名為setup.py。使用這種腳本,可安裝模塊、包和擴展。 |
Setuptools的命令 | 可使用多個命令來運行setup.py腳本,如build、build_ext、install、sdist和bdist。 |
編譯擴展 | 可使用Setuptools來自動編譯C語言擴展,并讓Setuptools自動確定Python安裝位置以及該使用哪個編譯器。還可讓它自動運行SWIG。 |
可執行的二進制文件 | Setuptools擴展py2exe可用來從Python程序創建可執行的Windows二進制文件以及其他一些文件(可使用安裝程序方便地安裝)。無需單獨安裝Python解釋器,就可運行這些.exe文件。在macOS中,擴展py2app提供了與py2exe類似的功能。 |
本章介紹的新函數
函數 | 描述 |
---|---|
setuptools.setup(…) | 在腳本setup.py中使用關鍵字參數配置Setuptools |