??Python在提供傻白甜這樣的編程方式的時候被饿,對性能就是硬傷了,所以性能這塊提供了C的擴展模塊,實際上Python是與本地二進制可執(zhí)行動態(tài)庫是無縫調(diào)用的。上一個主題解釋了Python調(diào)用動態(tài)庫要门,但是那一種方式需要太多C的知識,其實Python還提供了一種無縫自動的調(diào)用方式廓啊,在Python成為built-in實現(xiàn)欢搜。這個主題就介紹Python的C擴展。順便還介紹了怎么制作Python安裝包
Python的C擴展的模式
- 提示:只爭對Python3的情況說明谴轮,對Python2放棄了狂巢。
Python與C擴展動態(tài)庫之間的工作關(guān)系
- Python調(diào)用C動態(tài)庫的過程
- 編寫Python代碼
test.py
:import 模塊名
直接加載模塊; - Python虛擬機執(zhí)行
test.py
代碼书聚,會根據(jù)import的模塊名查找模塊唧领,模塊可以是是python模塊或者dll模塊,dll模塊查找規(guī)則是:模塊名.其他任意描述.pyd
雌续; - 查找到以后斩个,執(zhí)行
PyInit_模塊名
初始化函數(shù)完成dll的初始化; -
PyInit_模塊名
初始化函數(shù)完成python中函數(shù)名與擴展接口包裝函數(shù)名的映射驯杜; - 當調(diào)用模塊中函數(shù)的時候受啥,python會根據(jù)python函數(shù)名找到C擴展包裝函數(shù)名;
- C擴展包裝函數(shù)調(diào)用任意C實現(xiàn)的代碼。
- 編寫Python代碼
C動態(tài)庫的編譯
-
C的動態(tài)庫使用python的C庫與頭文件
- 實際沒有額外dll的庫滚局,所有代碼都封裝在h文件中居暖。
Python.h
structmember.h
- 實際沒有額外dll的庫滚局,所有代碼都封裝在h文件中居暖。
-
不同的平臺或者編譯器編譯的指令都有差異,但是編譯的結(jié)構(gòu)都是動態(tài)庫
- gcc是編譯so文件藤肢;(mac的clang編譯器可能是dylib)
- link是編譯dll文件太闺;
-
說明:
- 盡管是動態(tài)庫,但是Python擴展的工作規(guī)范是pyd擴展名嘁圈,不使用so省骂、dll、dylib文件名擴展名最住。
C擴展接口的編程模式
包裝函數(shù)實現(xiàn)
-
包裝函數(shù)可以自己實現(xiàn)钞澳,也可以調(diào)用C的其他實現(xiàn),包含C動態(tài)庫涨缚。下面是一個代碼例子轧粟,重點是:
- 包裝器函數(shù)形式三種:
- 一般參數(shù):
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
- 命名參數(shù):
typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *, PyObject *);
- 無參數(shù):
typedef PyObject *(*PyNoArgsFunction)(PyObject *);
- 一般參數(shù):
- 參數(shù)的轉(zhuǎn)換處理(把
PyObject*
類型轉(zhuǎn)換為C類型):- 解析命名參數(shù):
PyArg_ParseTupleAndKeywords
- 解析一般參數(shù):
PyArg_ParseTuple
- 解析命名參數(shù):
- 返回值得轉(zhuǎn)換處理:(如果已經(jīng)是
PyObject*
類型則不需要轉(zhuǎn)換)- 調(diào)用
Py_BuildValue
函數(shù)把C類型轉(zhuǎn)換為PyObject*
類型
- 調(diào)用
- 包裝器函數(shù)形式三種:
包裝器函數(shù)可以隨意命名,但是建議采用
模塊名_函數(shù)名
脓魏,我們使用的是py_函數(shù)名
逃延。
static char py_gcd_doc[] = "最大公約數(shù)";
static PyObject* py_gcd(PyObject*self, PyObject *args){
int r, x, y;
// 解析參數(shù)
if(!PyArg_ParseTuple(args, "ii:gcd", &x, &y)){
return NULL;
}
r = gcd(x, y);
return Py_BuildValue("i", r);
}
static char py_replace_doc[] = "字符替換";
static PyObject* py_replace(PyObject* self, PyObject *args, PyObject *kwargs){
char *s, *sdup;
char och, nch;
int nrep;
PyObject *result;
static char *argsname[] = {"s", "och", "nch", NULL};
// 解析參數(shù)
if(!PyArg_ParseTupleAndKeywords(args, kwargs, "scc:replace", argsname, &s, &och, &nch)){
return NULL;
}
sdup = (char *)malloc(strlen(s) + 1);
strcpy(sdup, s);
nrep = replace(sdup, och, nch);
result = Py_BuildValue("(is)", nrep, sdup);
free(sdup);
return result;
}
static char py_distance_doc[] = "計算距離";
static PyObject* py_distance(PyObject *self, PyObject *args){
PyErr_SetString(PyExc_NotImplementedError, "distance() not implements");
return NULL;
}
附錄:上面調(diào)用的三個函數(shù)的C實現(xiàn)
頭文件:C.h
#ifndef C_YQ_H
#define C_YQ_H
#include <stdio.h>
#include <string.h>
#include <math.h>
typedef struct Point{
double x;
double y;
} Point;
extern int gcd(int x, int y);
extern int replace(char *s, char och, char nch);
extern double distance(Point *a, Point *b);
#define MAGIC 0x31337
#endif
實現(xiàn)文件:C.c
#include "C.h"
int gcd(int x, int y){
/*
這個算法是來自最大公約數(shù)的一個性質(zhì)
gcd(a,b)=gcd(b, a mod b)
gcd(a,b)=gcd(b, a-b)
*/
int g;
g = y;
while(x > 0){
g = x;
x = y % x;
y = g;
}
return g;
}
int replace(char *s, char och, char nch){
int nrep = 0;
while(s = strchr(s, och)){
*(s++) = nch;
nrep++;
}
return nrep;
}
double distance(Point *a, Point *b){
double dx, dy;
dx = a->x - b->x;
dy = a->y - b->y;
return sqrt(dx * dx + dy * dy);
}
// 測試代碼調(diào)用的,編譯成執(zhí)行文件執(zhí)行:cl /EHsc /MD /utf-8 /nologo C.c /link /MACHINE:X64 /NOLOGO /OUT:main.exe
// int main(){
// printf("公約數(shù)是:%d\n", gcd(100,254));
// char *str = "Hello this is a world!";
// printf("替換次數(shù):%d\n", replace(str, 'i','X'));
// printf("替換結(jié)果:%s\n", str);
// Point a = {0, 1};
// Point b = {1, 0};
// printf("距離:%f\n", distance(&a, &b));
// return 0;
// }
定義模塊
PyModuleDef結(jié)構(gòu)體
- 模塊定義在Python的C擴展中是一個結(jié)構(gòu)體:
PyModuleDef
, 創(chuàng)建模塊的使用轧拄,就是使用這個定義模塊揽祥,這個結(jié)構(gòu)體的定義如下:
typedef struct PyModuleDef{
PyModuleDef_Base m_base;
const char* m_name;
const char* m_doc;
Py_ssize_t m_size;
PyMethodDef *m_methods;
struct PyModuleDef_Slot* m_slots;
traverseproc m_traverse;
inquiry m_clear;
freefunc m_free;
} PyModuleDef;
- 其中的核心是前面5個成員的定義是必須。
-
PyModuleDef_Base m_base;
- 這是指定基檩电,使用一個宏指定:
PyModuleDef_HEAD_INIT
- 這是指定基檩电,使用一個宏指定:
-
const char* m_name;
- 模塊名:這個名字也是編譯后的dll/so的名字拄丰。
-
const char* m_doc;
- 文檔,可以指定為NULL俐末。
-
Py_ssize_t m_size;
- 使用-1標識自動指定大小料按。
-
PyMethodDef *m_methods;
- 模塊中的方法/函數(shù)定義。這里指針是指的邊長動態(tài)數(shù)組卓箫。
-
PyMethodDef結(jié)構(gòu)體
- 模塊中導(dǎo)出的方法/函數(shù)定義, 使用結(jié)構(gòu)體定義:
PyMethodDef
struct PyMethodDef {
const char *ml_name; /* The name of the built-in function/method */
PyCFunction ml_meth; /* The C function that implements it */
int ml_flags; /* Combination of METH_xxx flags, which mostly
describe the args expected by the C func */
const char *ml_doc; /* The __doc__ attribute, or NULL */
};
typedef struct PyMethodDef PyMethodDef;
- PyMethodDef結(jié)構(gòu)體成員說明:
-
const char *ml_name
:- python中調(diào)用的函數(shù)名:
-
PyCFunction ml_meth;
:- C擴展包裝函數(shù)名载矿,其真正類型是
PyCFunction + PyCFunctionWithKeywords + PyNoArgsFunction
,為了防止編譯警告烹卒,需要類型轉(zhuǎn)換為PyCFunction
- C擴展包裝函數(shù)名载矿,其真正類型是
-
int ml_flags
:- 指定參數(shù)類型:
PyCFunction + PyCFunctionWithKeywords + PyNoArgsFunction
闷盔,使用對應(yīng)的宏#define METH_VARARGS 0x0001
#define METH_KEYWORDS 0x0002
#define METH_NOARGS 0x0004
- METH_VARARGS必須與METH_KEYWORDS聯(lián)合使用。
- 指定參數(shù)類型:
-
const char *ml_doc
:- 函數(shù)的文檔定義旅急。
-
模塊定義的例子
- 先定義:PyMethodDef逢勾,再定義:PyModuleDef
static PyMethodDef _mymethos[] = {
{"gcd", py_gcd, METH_VARARGS, py_gcd_doc},
{"replace", (PyCFunction)py_replace, METH_KEYWORDS | METH_VARARGS, py_replace_doc}, // 因為帶三個參數(shù),屬于PyCFunctionWithKeywords
{"distance", py_distance, METH_VARARGS, py_distance_doc},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef _mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule",
NULL,
-1,
_mymethos
};
創(chuàng)建模塊
- 創(chuàng)建模塊必須在導(dǎo)出函數(shù)中創(chuàng)建:
導(dǎo)出函數(shù)
-
導(dǎo)出函數(shù)規(guī)范:
-
PyMODINIT_FUNC PyInit_模塊名(void)
- 返回值:
PyMODINIT_FUNC
藐吮,本質(zhì)是PyObject指針類型,也就是是一個模塊對象溺拱,使用:模塊名.函數(shù)
可以在Python中調(diào)用逃贝。define PyMODINIT_FUNC __declspec(dllexport) PyObject*
- 參數(shù):無
- 函數(shù)名:
PyInit_
作為前綴,后面加上模塊名迫摔。模塊名以PyModuleDef對象中定義的名字為準沐扳。
- 返回值:
-
導(dǎo)出函數(shù)的例子:
PyMODINIT_FUNC PyInit_mymodule(void){
return PyMODINIT_FUNC對象;
}
創(chuàng)建模塊并返回
-
模塊創(chuàng)建使用函數(shù)PyModule_Create創(chuàng)建,函數(shù)原型是:
-
PyAPI_FUNC(PyObject *) PyModule_Create2(struct PyModuleDef*, int apiver);
- 第2個參數(shù)使用api把把版本句占,是固定的值:
#define PYTHON_API_VERSION 1013
- 第一個參數(shù)類型是:
PyModuleDef *
- 返回值:PyObject指針沪摄。
- 第2個參數(shù)使用api把把版本句占,是固定的值:
-
模塊撞見的例子:
PyMODINIT_FUNC PyInit_mymodule(void){
PyObject *mod;
mod = PyModule_Create(&_mymodule);
return mod;
}
Python的C擴展例子
- 提示:使用《Python參考手冊(第4版)》中第26章的例子。
C功能實現(xiàn)
C頭文件:C.h
#ifndef C_YQ_H
#define C_YQ_H
#include <stdio.h>
#include <string.h>
#include <math.h>
typedef struct Point{
double x;
double y;
} Point;
extern int gcd(int x, int y);
extern int replace(char *s, char och, char nch);
extern double distance(Point *a, Point *b);
#define MAGIC 0x31337
#endif
C實現(xiàn)文件:C.c
#include "C.h"
int gcd(int x, int y){
/*
這個算法是來自最大公約數(shù)的一個性質(zhì)
gcd(a,b)=gcd(b, a mod b)
gcd(a,b)=gcd(b, a-b)
*/
int g;
g = y;
while(x > 0){
g = x;
x = y % x;
y = g;
}
return g;
}
int replace(char *s, char och, char nch){
int nrep = 0;
while(s = strchr(s, och)){
*(s++) = nch;
nrep++;
}
return nrep;
}
double distance(Point *a, Point *b){
double dx, dy;
dx = a->x - b->x;
dy = a->y - b->y;
return sqrt(dx * dx + dy * dy);
}
// 測試代碼調(diào)用的辖众,編譯成執(zhí)行文件執(zhí)行:cl /EHsc /MD /utf-8 /nologo C.c /link /MACHINE:X64 /NOLOGO /OUT:main.exe
// int main(){
// printf("公約數(shù)是:%d\n", gcd(100,254));
// char *str = "Hello this is a world!";
// printf("替換次數(shù):%d\n", replace(str, 'i','X'));
// printf("替換結(jié)果:%s\n", str);
// Point a = {0, 1};
// Point b = {1, 0};
// printf("距離:%f\n", distance(&a, &b));
// return 0;
// }
C擴展實現(xiàn)
#include <Python.h>
#include "C.h"
static char py_gcd_doc[] = "最大公約數(shù)";
static PyObject* py_gcd(PyObject*self, PyObject *args){
int r, x, y;
// 解析參數(shù)
if(!PyArg_ParseTuple(args, "ii:gcd", &x, &y)){
return NULL;
}
r = gcd(x, y);
return Py_BuildValue("i", r);
}
static char py_replace_doc[] = "字符替換";
static PyObject* py_replace(PyObject* self, PyObject *args, PyObject *kwargs){
char *s, *sdup;
char och, nch;
int nrep;
PyObject *result;
static char *argsname[] = {"s", "och", "nch", NULL};
// 解析參數(shù)
if(!PyArg_ParseTupleAndKeywords(args, kwargs, "scc:replace", argsname, &s, &och, &nch)){
return NULL;
}
sdup = (char *)malloc(strlen(s) + 1);
strcpy(sdup, s);
nrep = replace(sdup, och, nch);
result = Py_BuildValue("(is)", nrep, sdup);
free(sdup);
return result;
}
static char py_distance_doc[] = "計算距離";
static PyObject* py_distance(PyObject *self, PyObject *args){
PyErr_SetString(PyExc_NotImplementedError, "distance() not implements");
return NULL;
}
static PyMethodDef _mymethos[] = {
{"gcd", py_gcd, METH_VARARGS, py_gcd_doc},
{"replace", (PyCFunction)py_replace, METH_KEYWORDS | METH_VARARGS, py_replace_doc}, // 因為帶三個參數(shù)卓起,屬于PyCFunctionWithKeywords
{"distance", py_distance, METH_VARARGS, py_distance_doc},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef _mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule",
NULL,
-1,
_mymethos
};
PyMODINIT_FUNC PyInit_mymodule(void){
PyObject *mod;
mod = PyModule_Create(&_mymodule);
PyModule_AddIntMacro(mod, MAGIC);
return mod;
}
編譯腳本
- 腳本:Makefile
pyd: C.c C.h C_ython.c
# 切換utf-8編碼
@chcp 65001
# 編譯C.c
@cl /c /EHsc /MD /utf-8 /nologo /Fo:C.obj C.c
# 編譯C_ython.c
@cl /c /EHsc /MD /utf-8 /nologo "-IC:\Program Files\Python36\include" /Fo:C_ython.obj C_ython.c
# 鏈接動態(tài)庫
@link /MACHINE:X64 /NOLOGO /DLL /OUT:mymodule.pyd /EXPORT:PyInit_mymodule C.obj C_ython.obj
clean:
@del *.obj *.dll *.pdb *.ilk *.exe *.lib *.exp *.pyd 2>/Nula
- 執(zhí)行腳本:
vcvars64.bat
nmake pyd
- 注意:
- vcvars64.bat安裝
Visual Studio
后就有的一個C++編譯環(huán)境配置腳本和敬。
- vcvars64.bat安裝
- 編譯效果
Python調(diào)用代碼
- Python調(diào)用就像Python語法一樣
# 模塊導(dǎo)入
import mymodule
# 模塊調(diào)用
print(mymodule.gcd(6, 8))
Python執(zhí)行效果
- 執(zhí)行python:
python test.py
- 在Linux下凹炸,直接使用腳本執(zhí)行更加方便。
觀察下pyd的導(dǎo)出信息
- 從此C的動態(tài)庫可以作為Python模塊的擴展形式存在昼弟,與Python模塊一樣的使用啤它。
- 這也是所謂built-in內(nèi)置函數(shù)與類的實現(xiàn)機制與來源。不見代碼舱痘,只見模塊。真是酸爽啊墓阀!
C擴展的核心
- C擴展都是有編程模式的舆驶,模式清楚后,剩余的就是參數(shù)與返回值的類型處理旬盯,這是最大的麻煩台妆。后面單獨開一個主題說明。
Python的擴展編譯
- 上面的內(nèi)容完全是利用C的編程技術(shù)胖翰,包含Python的C擴展接口技術(shù)接剩,實際Python提供了更多自動化的工作機制
擴展編譯
- 擴展編譯就是不需要自己編寫Makefile這樣的編譯腳本,而是Python自動提供編譯配置萨咳。
setup.py文件模式
- setup.py文件一般編程模式
from distutils.core import setup, Extension
setup(
name="my",
version="1.1",
ext_modules=[
Extension("mymodule", sources=["C_ython.c", "C.c"],language="C"),
]
)
- 那么是包名
setup函數(shù)
- setup函數(shù)是一個setup腳本需要的工作設(shè)置懊缺。
from distutils.core import setup, Extension
help(setup)
Help on function setup in module distutils.core:
setup(**attrs)
The gateway to the Distutils: do everything your setup script needs
to do, in a highly flexible and user-driven way. Briefly: create a
Distribution instance; find and parse config files; parse the command
line; run each Distutils command found there, customized by the options
supplied to 'setup()' (as keyword arguments), in config files, and on
the command line.
The Distribution instance might be an instance of a class supplied via
the 'distclass' keyword argument to 'setup'; if no such class is
supplied, then the Distribution class (in dist.py) is instantiated.
All other arguments to 'setup' (except for 'cmdclass') are used to set
attributes of the Distribution instance.
The 'cmdclass' argument, if supplied, is a dictionary mapping command
names to command classes. Each command encountered on the command line
will be turned into a command class, which is in turn instantiated; any
class found in 'cmdclass' is used in place of the default, which is
(for command 'foo_bar') class 'foo_bar' in module
'distutils.command.foo_bar'. The command class must provide a
'user_options' attribute which is a list of option specifiers for
'distutils.fancy_getopt'. Any command-line options between the current
and the next command are used to set attributes of the current command
object.
When the entire command-line has been successfully parsed, calls the
'run()' method on each command object in turn. This method will be
driven entirely by the Distribution object (which each command object
has a reference to, thanks to its constructor), and the
command-specific options that became attributes of each command
object.
setup.py的常見任務(wù)
C:\01works\13python\codes\cython_py>python setup.py --help-commands
Standard commands:
build build everything needed to install
build_py "build" pure Python modules (copy to build directory)
build_ext build C/C++ extensions (compile/link to build directory)
build_clib build C/C++ libraries used by Python extensions
build_scripts "build" scripts (copy and fixup #! line)
clean clean up temporary files from 'build' command
install install everything from build directory
install_lib install all Python modules (extensions and pure Python)
install_headers install C/C++ header files
install_scripts install scripts (Python or otherwise)
install_data install data files
sdist create a source distribution (tarball, zip file, etc.)
register register the distribution with the Python package index
bdist create a built (binary) distribution
bdist_dumb create a "dumb" built distribution
bdist_rpm create an RPM distribution
bdist_wininst create an executable installer for MS Windows
check perform some checks on the package
upload upload binary package to PyPI
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
- 我們主要使用build_ext
build_ext的選項
C:\01works\13python\codes\cython_py>python setup.py build_ext --help
Common commands: (see '--help-commands' for more)
setup.py build will build the package underneath 'build/'
setup.py install will install the package
Global options:
--verbose (-v) run verbosely (default)
--quiet (-q) run quietly (turns verbosity off)
--dry-run (-n) don't actually do anything
--help (-h) show detailed help message
--no-user-cfg ignore pydistutils.cfg in your home directory
Options for 'build_ext' command:
--build-lib (-b) directory for compiled extension modules
--build-temp (-t) directory for temporary files (build by-products)
--plat-name (-p) platform name to cross-compile for, if supported
(default: win-amd64)
--inplace (-i) ignore build-lib and put compiled extensions into the
source directory alongside your pure Python modules
--include-dirs (-I) list of directories to search for header files
(separated by ';')
--define (-D) C preprocessor macros to define
--undef (-U) C preprocessor macros to undefine
--libraries (-l) external C libraries to link with
--library-dirs (-L) directories to search for external C libraries
(separated by ';')
--rpath (-R) directories to search for shared C libraries at runtime
--link-objects (-O) extra explicit link objects to include in the link
--debug (-g) compile/link with debugging information
--force (-f) forcibly build everything (ignore file timestamps)
--compiler (-c) specify the compiler type
--parallel (-j) number of parallel build jobs
--swig-cpp make SWIG create C++ files (default is C)
--swig-opts list of SWIG command line options
--swig path to the SWIG executable
--user add user include, library and rpath
--help-compiler list available compilers
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
Extension類
from distutils.core import setup, Extension
help(Extension)
Help on class Extension in module distutils.extension:
class Extension(builtins.object)
| Just a collection of attributes that describes an extension
| module and everything needed to build it (hopefully in a portable
| way, but there are hooks that let you be as unportable as you need).
|
| Instance attributes:
| name : string
| the full name of the extension, including any packages -- ie.
| *not* a filename or pathname, but Python dotted name
| sources : [string]
| list of source filenames, relative to the distribution root
| (where the setup script lives), in Unix form (slash-separated)
| for portability. Source files may be C, C++, SWIG (.i),
| platform-specific resource files, or whatever else is recognized
| by the "build_ext" command as source for a Python extension.
| include_dirs : [string]
| list of directories to search for C/C++ header files (in Unix
| form for portability)
| define_macros : [(name : string, value : string|None)]
| list of macros to define; each macro is defined using a 2-tuple,
| where 'value' is either the string to define it to or None to
| define it without a particular value (equivalent of "#define
| FOO" in source or -DFOO on Unix C compiler command line)
| undef_macros : [string]
| list of macros to undefine explicitly
| library_dirs : [string]
| list of directories to search for C/C++ libraries at link time
| libraries : [string]
| list of library names (not filenames or paths) to link against
| runtime_library_dirs : [string]
| list of directories to search for C/C++ libraries at run time
| (for shared extensions, this is when the extension is loaded)
| extra_objects : [string]
| list of extra files to link with (eg. object files not implied
| by 'sources', static library that must be explicitly specified,
| binary resource files, etc.)
| extra_compile_args : [string]
| any extra platform- and compiler-specific information to use
| when compiling the source files in 'sources'. For platforms and
| compilers where "command line" makes sense, this is typically a
| list of command-line arguments, but for other platforms it could
| be anything.
| extra_link_args : [string]
| any extra platform- and compiler-specific information to use
| when linking object files together to create the extension (or
| to create a new static Python interpreter). Similar
| interpretation as for 'extra_compile_args'.
| export_symbols : [string]
| list of symbols to be exported from a shared extension. Not
| used on all platforms, and not generally necessary for Python
| extensions, which typically export exactly one symbol: "init" +
| extension_name.
| swig_opts : [string]
| any extra options to pass to SWIG if a source file has the .i
| extension.
| depends : [string]
| list of files that the extension depends on
| language : string
| extension language (i.e. "c", "c++", "objc"). Will be detected
| from the source extensions if not provided.
| optional : boolean
| specifies that a build failure in the extension should not abort the
| build process, but simply not install the failing extension.
|
| Methods defined here:
|
| __init__(self, name, sources, include_dirs=None, define_macros=None, undef_macros=None, library_dirs=None, libraries=None, runtime_library_dirs=None, extra_objects=None, extra_compile_args=None, extra_link_args=None, export_symbols=None, swig_opts=None, depends=None, language=None, optional=None, **kw)
| Initialize self. See help(type(self)) for accurate signature.
|
| __repr__(self)
| Return repr(self).
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
擴展編譯結(jié)果
- 執(zhí)行命令:
python setup.py build_ext --inplace
這個編譯不需要執(zhí)行vcvars64,因為所有的選項都這是在命令行了培他。
然后執(zhí)行test.py測試下效果鹃两,這個與直接用C編譯器編譯的調(diào)用一樣。
-
更多的setup.py使用舀凛,請參考:
https://thomasnyberg.com/cpp_extension_modules.html
https://packaging.python.org/guides/packaging-binary-extensions/
https://packaging.python.org/tutorials/packaging-projects/
包裝擴展模塊的Python模塊
- 一般不直接調(diào)用Python的C擴展模塊怔毛,一般會使用Python包裝一下。
- 包裝模塊
- 文件名:
my.py
- 文件名:
from mymodule import *
- 調(diào)用模塊
test.py
import my
print(my.gcd(6, 8))
安裝
安裝的目錄結(jié)構(gòu)
一定要清楚自己需要安裝什么腾降,目錄結(jié)構(gòu)需要清楚拣度。
-
安裝包含兩種類型的文件:
- Python的代碼
- Python的擴展模塊(直接執(zhí)行Python模塊也可以)
-
下面是需要安裝的目錄包
- 需要編譯安裝的Python的C擴展模塊源代碼
- C.h
- C.c
- C_ython.c
- python的封裝代碼(包方式,模塊的包需要init.py文件,沒有內(nèi)容就空文件)
- my.py
- 注意:為了更好理解子包安裝抗果,這里畫蛇添足的增加了有個子包mypkg
- 測試的腳本代碼
- test.py
- 需要編譯安裝的Python的C擴展模塊源代碼
安裝腳本文件setup.py
from distutils.core import setup, Extension
setup(
name="mydemos", # 用于pip安裝中指定的名字
version="1.1",
packages=["mydemo", "mydemo.mypkg"], # 包路徑下一定要有__init__.py
scripts=["test.py"],
ext_modules=[
Extension("mymodule", sources=["C_ython.c", "C.c"],language="C"), # 需要安裝的python擴展模塊
]
)
直接安裝
命令:
python setup.py install
安裝過程
- 安裝結(jié)果
- Python的C擴展模塊
- Python包與模塊
- 使用pip list也能查看到安裝的模塊
- 執(zhí)行測試
- 注意使用包的方式筋帖,訪問擴展模塊就需要多幾個包了,下面是在IPython環(huán)境下測試冤馏,在非交互式編程也是一樣的日麸。
安裝打包
- 命令:
python setup.py sdist
- 使用安裝就非常簡單了,直接解壓逮光,然后調(diào)用
python setup.py install
就ok代箭。
附錄
如果包路徑比較分散:可以使用:package_dir選項配置。這里就不舉例子了涕刚。
requires可以指定依賴模塊嗡综。
data_files提供數(shù)據(jù)文件。