1. 程式人生 > >python基礎教程(第三版)學習筆記(十八)

python基礎教程(第三版)學習筆記(十八)

第十八章 程式打包

本章重點介紹Setuptools,因為這是每個Python程式設計師都要用到的工具。實際上,Setuptools 並非只能用於建立基於指令碼的Python安裝程式,還可用於編譯擴充套件。另外,通過將其與擴充套件py2exe 和py2app結合起來使用,還可建立獨立的Windows和macOS可執行程式。

18.1 Setuptools 基礎

安裝setuptools:

C:\Windows\system32>pip install setuptools Requirement already satisfied: setuptools in c:\python37\lib\site-packages (39.0.1)

簡單的Setuptools安裝指令碼(setup.py)

#setup.py from setuptools import setup setup(name='Hello', version='1.0', py_modules=['hello']) ​

執行結果:

usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]   or: setup.py --help [cmd1 cmd2 ...]   or: setup.py --help-commands   or: setup.py cmd --help ​ error: no commands supplied ​ ​ ------------------ (program exited with code: 1) ​ 請按任意鍵繼續. . . ​
​
​

同時在setup.py所在的目錄中建立了一個pycache新的目錄,其內包含一個setup.cpython-37.pyc檔案。

試執行命令 build 執行結果:

E:\pythonProjects>python setup.py build running build running build_py creating build creating build\lib copying hello.py -> build\lib ​ E:\pythonProjects>

建立了build目錄且在其中包含了原始檔hello.py。

執行install命令結果:

E:\pythonProjects>python setup.py install running install running bdist_egg running egg_info creating Hello.egg-info writing Hello.egg-info\PKG-INFO writing dependency_links to Hello.egg-info\dependency_links.txt writing top-level names to Hello.egg-info\top_level.txt writing manifest file 'Hello.egg-info\SOURCES.txt' reading manifest file 'Hello.egg-info\SOURCES.txt' writing manifest file 'Hello.egg-info\SOURCES.txt' installing library code to build\bdist.win-amd64\egg running install_lib running build_py creating build\bdist.win-amd64 creating build\bdist.win-amd64\egg copying build\lib\hello.py -> build\bdist.win-amd64\egg byte-compiling build\bdist.win-amd64\egg\hello.py to hello.cpython-37.pyc creating build\bdist.win-amd64\egg\EGG-INFO copying Hello.egg-info\PKG-INFO -> build\bdist.win-amd64\egg\EGG-INFO copying Hello.egg-info\SOURCES.txt -> build\bdist.win-amd64\egg\EGG-INFO copying Hello.egg-info\dependency_links.txt -> build\bdist.win-amd64\egg\EGG-IN O copying Hello.egg-info\top_level.txt -> build\bdist.win-amd64\egg\EGG-INFO zip_safe flag not set; analyzing archive contents... creating dist creating 'dist\Hello-1.0-py3.7.egg' and adding 'build\bdist.win-amd64\egg' to i ​ removing 'build\bdist.win-amd64\egg' (and everything under it) Processing Hello-1.0-py3.7.egg Copying Hello-1.0-py3.7.egg to c:\python37\lib\site-packages Adding Hello 1.0 to easy-install.pth file ​ Installed c:\python37\lib\site-packages\hello-1.0-py3.7.egg Processing dependencies for Hello==1.0 Finished processing dependencies for Hello==1.0 ​ E:\pythonProjects>

同時在python的安裝第三方包目錄下產生了一個相應的egg檔案;在專案目錄中產生了一個Hello.egg-info目錄和dist目錄。Hello.egg-info中包含了一些資訊檔案;dist中則包含一個和在python的安裝第三方包目錄下產生的egg檔案相同的檔案。

18.2 打包

編寫讓使用者能夠安裝模組的指令碼setup.py後,就可使用它來建立歸檔檔案了。你還可使用它 來建立Windows安裝程式、RPM包、egg檔案、wheel檔案等。

要建立原始碼歸檔檔案,可使用命令sdist :

E:\pythonProjects>python setup.py sdist running sdist running egg_info writing Hello.egg-info\PKG-INFO writing dependency_links to Hello.egg-info\dependency_links.txt writing top-level names to Hello.egg-info\top_level.txt reading manifest file 'Hello.egg-info\SOURCES.txt' writing manifest file 'Hello.egg-info\SOURCES.txt' warning: sdist: standard file not found: should have one of README, README. README.txt, README.md ​ running check warning: check: missing required meta-data: url ​ warning: check: missing meta-data: either (author and author_email) or (mai er and maintainer_email) must be supplied ​ creating Hello-1.0 creating Hello-1.0\Hello.egg-info copying files to Hello-1.0... copying hello.py -> Hello-1.0 copying setup.py -> Hello-1.0 copying Hello.egg-info\PKG-INFO -> Hello-1.0\Hello.egg-info copying Hello.egg-info\SOURCES.txt -> Hello-1.0\Hello.egg-info copying Hello.egg-info\dependency_links.txt -> Hello-1.0\Hello.egg-info copying Hello.egg-info\top_level.txt -> Hello-1.0\Hello.egg-info Writing Hello-1.0\setup.cfg Creating tar archive removing 'Hello-1.0' (and everything under it)
​同時在dist目錄下建立了一個.tar.gz的安裝檔案!

18.3 編譯擴充套件

第17章介紹瞭如何編寫Python擴充套件。你可能也認為這些擴充套件編譯起來有點麻煩,所幸 Setuptools也可用來完成這種任務。你可能想回過頭去看看第17章中程式palindrome的原始碼。假設這個原始碼檔案(palindrome2.c)位於當前目錄中,則可使用下面的setup.py 指令碼來編譯(並安裝)它:

 

/*palindrome2.c*/
#include <Python.h>
static PyObject *is_palindrome(PyObject *self, PyObject *args) {
 int i, n;
 const char *text;
 int result;
 /* "s"表示一個字串:*/
 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;
 }
 }
 /* "i"表示一個整數:*/
 return Py_BuildValue("i", result);
}
/* 方法/函式列表:*/
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, Extension
setup(name='palindrome',
 version='1.0',
 ext_modules = [
 Extension('palindrome', ['palindrome2.c'])
 ])

如果在編譯器中直接執行setup.py或者在終端中僅輸入python setup.py將會出現如下錯誤:

usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
   or: setup.py --help [cmd1 cmd2 ...]
   or: setup.py --help-commands
   or: setup.py cmd --help

error: no commands supplied


------------------
(program exited with code: 1)

請按任意鍵繼續. . .
提示你沒有輸入命令。必須在終端中輸入python setup.py install安裝命令。但是如果系統中沒有安裝Microsoft Visual C++ 14.0,同樣會出現錯誤提示:
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++
Build Tools": https://visualstudio.microsoft.com/downloads/

正確的結果形如:

E:\pythonProjects>python setup.py install
running install
running bdist_egg
running egg_info
writing palindrome.egg-info\PKG-INFO
writing dependency_links to palindrome.egg-info\dependency_links.txt
writing top-level names to palindrome.egg-info\top_level.txt
reading manifest file 'palindrome.egg-info\SOURCES.txt'
writing manifest file 'palindrome.egg-info\SOURCES.txt'
installing library code to build\bdist.win-amd64\egg
running install_lib
running build_ext
building 'palindrome' extension
creating build\temp.win-amd64-3.7
creating build\temp.win-amd64-3.7\Release
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_amd64\cl.exe /c
nologo /Ox /W3 /GL /DNDEBUG /MD -IC:\Python37\include -IC:\Python37\include "-I
:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE" "-IC:\Program Fi
es (x86)\Windows Kits\10\include\10.0.10240.0\ucrt" "-IC:\Program Files (x86)\W
ndows Kits\8.1\include\shared" "-IC:\Program Files (x86)\Windows Kits\8.1\inclu
e\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\winrt" /Tcpalindrome2.
 /Fobuild\temp.win-amd64-3.7\Release\palindrome2.obj
palindrome2.c
palindrome2.c(12): warning C4267: '=': conversion from 'size_t' to 'int', possi
le loss of data
creating E:\pythonProjects\build\lib.win-amd64-3.7
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_amd64\link.exe /
ologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:
:\Python37\libs /LIBPATH:C:\Python37\PCbuild\amd64 "/LIBPATH:C:\Program Files (
86)\Microsoft Visual Studio 14.0\VC\LIB\amd64" "/LIBPATH:C:\Program Files (x86)
Windows Kits\10\lib\10.0.10240.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Win
ows Kits\8.1\lib\winv6.3\um\x64" /EXPORT:PyInit_palindrome build\temp.win-amd64
3.7\Release\palindrome2.obj /OUT:build\lib.win-amd64-3.7\palindrome.cp37-win_am
64.pyd /IMPLIB:build\temp.win-amd64-3.7\Release\palindrome.cp37-win_amd64.lib
palindrome2.obj : warning LNK4197: export 'PyInit_palindrome' specified multipl
 times; using first specification
   Creating library build\temp.win-amd64-3.7\Release\palindrome.cp37-win_amd64.
ib and object build\temp.win-amd64-3.7\Release\palindrome.cp37-win_amd64.exp
Generating code
Finished generating code
creating build\bdist.win-amd64\egg
copying build\lib.win-amd64-3.7\palindrome.cp37-win_amd64.pyd -> build\bdist.wi
-amd64\egg
creating stub loader for palindrome.cp37-win_amd64.pyd
byte-compiling build\bdist.win-amd64\egg\palindrome.py to palindrome.cpython-37
pyc
creating build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\PKG-INFO -> build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\SOURCES.txt -> build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\dependency_links.txt -> build\bdist.win-amd64\egg\E
G-INFO
copying palindrome.egg-info\top_level.txt -> build\bdist.win-amd64\egg\EGG-INFO
writing build\bdist.win-amd64\egg\EGG-INFO\native_libs.txt
zip_safe flag not set; analyzing archive contents...
__pycache__.palindrome.cpython-37: module references __file__
creating 'dist\palindrome-1.0-py3.7-win-amd64.egg' and adding 'build\bdist.win-
md64\egg' to it
removing 'build\bdist.win-amd64\egg' (and everything under it)
Processing palindrome-1.0-py3.7-win-amd64.egg
creating c:\python37\lib\site-packages\palindrome-1.0-py3.7-win-amd64.egg
Extracting palindrome-1.0-py3.7-win-amd64.egg to c:\python37\lib\site-packages
Adding palindrome 1.0 to easy-install.pth file

Installed c:\python37\lib\site-packages\palindrome-1.0-py3.7-win-amd64.egg
Processing dependencies for palindrome==1.0
Finished processing dependencies for palindrome==1.0

E:\pythonProjects>

以上結果很清楚說明了egg檔案安裝成功:

Installed c:\python37\lib\site-packages\palindrome-1.0-py3.7-win-amd64.egg

同樣在專案目錄下也會產生一個包含諸多資訊的資訊目錄,同時在安裝目錄下也會產生相應的目錄。至此python就可以毫無顧忌的引用C/++語言編寫的函式(類)等要素了。如果系統安裝了SWIG再編輯一個.i介面檔案,它將產生一個.so檔案 ,這就不需要象第十七章所講的那樣繁瑣,就能輕而易舉的把C/C++與Python聯絡在一起了。

18.4 使用 py2exe 建立可執行程式

py2exe是Setuptools的一個擴充套件(可通過pip來安裝它),讓你能夠建立可執行的Windows程式 (.exe檔案)。

打包exe檔案:1)在setup.py中加入

... ... 
import py2exe
 ... ...

在setup.py所在的目錄執行終端,並輸入如下命令

python setup.py py2exe

既能建立控制檯程式。

使用py2app建立macOS控制檯程式的方法大致與此相同。

(至此python語言所有技能敘述完了,留下了不少遺憾和錯誤。其實它的每一章都可以是一本厚厚的書,不可能事無鉅細,這本書的目的是領路,不會陪你到天亮的。但程式設計關鍵是閱讀和練習,閱讀資料、原始碼及別人的編碼;自己勤動手寫,最終把這門語言融匯到血液裡)