Skip navigation.

crocodile's blog

a python lover

Posts tagged with "python"

Python descriptor的理解

相对于decorator, iterator, generator, metaclass 这些概念,descriptor是python所有概念中最难理解的一个了。尽管python documentation对其描述不多(基本上是一笔带过),以至于很多人忽略了这个概念。事实上,自己以前也忽略了它,只不过最近重温python时无意间发现了他,觉得非常有必要深入研究它。

自己的理解是建立在前人的基础之上的。不过,网上关于descriptor的资料实在是有限,下面是自己认为有参考价值的几个链接:
1.http://users.rcn.com/python/download/Descriptor.htm (最主要的参考资料)
2.http://www.python.org/peps/pep-0252.html (太难理解了)
3.http://www.python.org/~jeremy/weblog/030425.html
4.http://www.python.org/download/releases/2.2.2/descrintro/
5.Python25 documentation (Python Reference Manual, Chapter 3.4.2)
6.Python25的源代码

1.假如"x"是普通属性。
每个class均有一个__dict__,该class的obj也有一个__dict__。
1)对于obj.x,优先查找obj.__dict__["x"],如果找不到,再查找class.__dict__["x"];
2)对于class.x,直接查找class.__dict__["x"];
3)obj.__dict__与class.__dict__可以拥有同名的属性;
4)obj.x=10,将无条件的更新obj.__dict__;class.x=10,将无条件的更新class.__dict__。

class C(object):
x = 10

b = C() #b.__dict__不包含"x",C.__dict__包含"x"
b.x #10
C.x #10
b.x=100 #b.__dict__也包含一个"x",对应的值为100;C.__dict__对应的值还是10
b.x #100
C.x #10
t=C()
t.x #10
C.x=99 #C.__dict__["x"]变成了99
t.x #99
b.x #100
C.x #99

2.假如"x"是一个descriptor
为简化,假设obj.__dict__没有"x"项。

class RevealAccess(object):
def __init__(self, initval, name):
self.val = initval
self.name = name

def __get__(self, obj, objtype):
print 'Retrieving', self.name
return self.val

def __set__(self, obj, val):
print 'Updating' , self.name
self.val = val

class C(object):
x = RevealAccess(10,"A test variable")


>>> b = C() # case1
>>> b.x
Retrieving A test variable
10
>>> C.x
Retrieving A test variable
10
>>>
>>> b.x=100 # case2
Updating A test variable
>>> b.x
Retrieving A test variable
100
>>> C.x
Retrieving A test variable
100
>>>
>>> C.x=1000 # case3
>>>
>>> b.x
1000
>>> C.x
1000
>>> # case4
>>> C.x = RevealAccess(999,"The second var")
>>> b.x
Retrieving The second var
999
>>> C.x
Retrieving The second var
999
>>>

上述结果可以通过Python25 Documentation (Python Reference Manual, Chapter 3.4.2.2)解释:
The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in the class dictionary of another new-style class, known as the owner class. In the examples below, ``the attribute'' refers to the attribute whose name is the key of the property in the owner class' __dict__. Descriptors can only be implemented as new-style classes themselves.

1)__get__( self, instance, owner)
Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise an AttributeError exception.
(注意:obj.x、class.x均会导致该调用)

2)__set__( self, instance, value)
Called to set the attribute on an instance instance of the owner class to a new value, value.
(注意:仅obj.x=ttt均会导致该调用;class.x=ttt直接绑定到另外一个对象上)

3)__delete__( self, instance)
Called to delete the attribute on an instance instance of the owner class.


为简化以及方面理解,在实际应用中,尽量避免obj.__dict__与class.__dict__拥有同名的属性。


3.假如"x"是一个descriptor,而且obj.__dict__也有一个"x"项。非常复杂。
For instance bindings, the precedence of descriptor invocation depends on the which descriptor methods are defined. Data descriptors define both __get__() and __set__(). Non-data descriptors have just the __get__() method. Data descriptors always override a redefinition in an instance dictionary. In contrast, non-data descriptors can be overridden by instances.

详细的描述还得参考:http://users.rcn.com/python/download/Descriptor.htm

1)从该文档可以知道,descriptor与__getattribute__密切相关。基础类型object、type均定义了__getattribute__,并有缺省实现。上面所说的descriptor的各种特性其实就是这些__getattribute__的行为。也就是说,如果自己重新定义了__getattribute__,那么这个函数具有最高的优先级。

2)另外,__getattr__/__setattr__/__delattr__也与属性的取值有关,见Python25 documentation (Python Reference Manual, Chapter 3.4.2)。它们的级别比较低。建议它们所对应的属性不要为descriptor。

class RevealAccess(object):
def __init__(self, initval, name):
self.val = initval
self.name = name

def __get__(self, obj, objtype):
print 'Retrieving', self.name
return self.val


class C(object):
x = RevealAccess(10,"A test variable")
def __init__(self,val):
self.x = val

>>> b = C(100)
>>>
>>> C.x
Retrieving A test variable
10
>>> b.x
100
>>>


4.根据http://users.rcn.com/python/download/Descriptor.htm的描述,descriptor更多的被python自己用来实现一些语言上的特性。比如:function/property/staticmethod/classmethod/均是通过descriptor实现的。

glade+pygtk 试用札记

, ,

由于用python写程序,我已经考察过了好几种python的界面编写包,默认的tcl/tk,wxWindow,近来又试用pygtk。感觉用 pygtk是最顺手的,大约是因为我不熟悉c++而更熟悉c和callback吧。在加上glade编辑界面非常迅速方便,我更喜欢这个python+ pygtk+glade的组合了。
gtk的大名相信不用我多介绍,gnome就是用它开发的,pygtk是gtk的python接口封装(反正就是在python中调用gtk,具体名称是什么我也没弄清楚)。glade是gtk的界面编辑工具,不象我们在win下熟悉的vb,c++builder等IDE,glade只管生产界面和产生相关的代码,至于编译和代码编写,你还需要vim,gcc等其它工具。glade生成的是.glade文件,内容是xml,描述了界面的控件和布局;配合特定的代码生产器,它可以产生出对应各种语言的原代码,我所装的window版本有devc++和vc的生产器,我试了一下devc++的,glade产生的工程和代码可以马上编译运行,得到的界面和glade中的设计分毫不差。我也找到了for python的代码生成器,但是相比之下我更喜欢用glade文件动态生产界面,也就是不产生直接定义控件的python或c代码,而是用 libglade在程序启动时读取.glade文件生产界面。
在使用pygtk一前我做了很多搜索,我搜索到的文章似乎都比较旧,介绍的pygtk for win32的方法现在已经都不适用了,他们给了我很多警告,需要下载很多各种文件,但我自己安装时却什么困难都没有遇到,直接的下载了gtk-win32 -devel-2.8.6-rc3,pygtk-2.8.2-1.win32-py2.4安装后重启就可以了(虽然它没有警告你,gtk-win32安装后一定要重启,一些注册表项才能起作用,如果不重启,写出的程序会说某个函数在dll中找不着,我开始以为是bug,折腾了个把小时,由于死机才算搞懂了:-()。

好了下面开始介绍glade和pygtk的使用。
gtk-win32-devl-2.8.4-rc3已经包含了glade,gtk,libgalde等几个工具和库文件。安装后glade马上就能使用,但库的调用却要求必须重启。使用glade作界面是比较简单的(我也只使用了一些简单的功能,table我都没有用到。)glade的控制可以分为两类: box是用来调整布局的,有hbox和vbox两中,h和v就是水平和垂直的意思;box是不可见的,真正的控件如按钮和输入筐等就放在box上面,也就是说box负责分割窗口,其它控件负责交互。一个窗口总是先被其中一种布局的box分割成几行(或列),然后再在一个行(或列)中细分。box的属性窗中有个size项,代表的就是你把窗口或上一级的box分成了几份,如果开始时分少了可以修改这个值,多分出几份来,反之也可以减少几份。一个非box的控件必须占据一个box,所以你可以规划如何用box分割窗口,按层次关系把控件拉进box中。由于在只有box时无法调整box的大小(他们总是平分上一级的box),所以你必须想好先要水平还是垂直的分割窗口;做了一次分割后就把不需要在细分的box的控件放进去,然后再来做余下的分割。在使用 glade时最好把widget tree窗口也调出,点击box的一个格时,是不能选中box的,必须在widget tree中选中box才行,我发现combobox控件也有这个问题。用hbox分割vbox的一格时,控件会拉得很高,这时可以把hbox的 Expand和Fill属性设成No,控件就会缩回到他们应有的高度。properties窗口可以设定各个控件需要响应的信号,设定回调函数,也就是 delphi中的事件响应函数,如按钮的点解事件,窗口的关闭事件等。glade的使用是比较直观和简单的,用过delphi和vc的人估计都能马上明白如何使用。做好界面布局后保存工程,.glade文件就会生成,使用build项就会产生对应的c代码。
虽然我装的glade没有for python的代码生成器,但我们有更简单的方案--libglade,通过.glade文件动态生成代码。在我搜到的文章中,介绍的的libglade 是要单独的import进来的,但新的pygtk似乎已经集成了libglade, import gtk后可以用以下的一句话调出界面:
self.comWin=gtk.glade.XML("pycom.glade","mainWin")
在这里pycom.glade是我的glade生成的界面描述文件,mainWin就是窗口的名字,由于一个glade文件可以包含了多个窗口的描述,所以你需要指定是调出那个窗口。然后,我们可以马上把回调信号和你的python函数用signal_autoconnect链接起来:
self.comWin.signal_autoconnect(self.signals_dict)
signal_dict是信号和pythong函数的对应字典:
# signals_dict={
# "on_openButton_clicked":btOpenClick,
# "on_sentButton_clicked":btSentClick,
# "on_sentFileButton_clicked":btSentFileClick
# }
用这个办法可以用最小的代码初始化程序,但它有一个坏处(也可能是我还没有弄懂),pythong函数不能把self对象传递进函数中,传递进来的只有发生信号的控件指针。所以我没有用asignal_autoconnent函数,而是把控件逐一取出,把信号和响应函数链接起来:
button=self.comWin.get_widget("sentButton")
button.connect("clicked",self.btSentClick
btSentClick定义如下(如果用signal_autoconnet则不能有self参数,对象指针就传不进函数中,处理起来很麻烦,希望有高手来说说有没有更好的办法。):
def btSentClick(self,widget)
程序中我还试用了gtk的idel函数和定时处理函数,前者在空闲时被调用,后者则每隔一定时间被执行一次,我用他们来做串口的接收。虽然我也写了另一个线程做接收,但为简化程序而没有用上,线程代码虽然能用,但是有bug的,会出错,而空闲函数对低速的串口也能很好的响应。
总之pygtk+glade给我的感觉是个不错的开发界面的组合,而且开发出来的界面还可以被其它语言使用,在加上gtk包的广泛应应用,使用这个组合是个很不错的选择。
下面是window下的pygtk和glade的下载地址,我的程序的文件和代码在资源中心的pycom.rar中。

http://www.pygtk.org
http://www.pcpm.ucl.ac.be/~gustin/win32_ports/
http://gladewin32.sourceforge.net/modules/news/

c中嵌入python的简单例子

, ,

其实主要是复习gcc的用法
#include <Python.h>

int main(void){
    Py_Initialize();
    PyRun_SimpleString("from time import time,ctime\n"
                        "print 'Today is',ctime(time()\n)");
    Py_Finalize();
    return 1;

}

假定python2.4安装在/opt/python目录下
gcc -I/opt/python/include/python2.4 -L/opt/python/lib -lpython2.4 -o test_py test_py.c

为python编写c/c++ 的extension

python是现在比较流行的编程语言,使用非常容易,功能也很强大,但是执行效率较c或c++差很多,在写某些项目的时候可以先用python把软件框架快速搭建起来,然后用c或者c++改写某些瓶颈模块,使得软件的效率跟c或c++的编制的代码相差无几,从而达到性能和快速开发的平衡。或者将某些c和c++编制的老代码重新封装一下,使python直接调用,从而达到软件复用的目的。
但是怎么让python直接调用c或者c++编写的代码呢,其实很简单,只需写一个封装文件,作为python和c/c++程序直接的接口。
1 数据的转换
python其实就是c语言编写的,它是一种面向对象的语言,把任何数据结构都解释为对象,变量是对象,类是对象,函数是对象,统统都是对象,所以编写接口程序的时候要理解的是c/c++程序的变量转换为python的变量的时候需要把c/c++的变量转换为python 的对象,在python里边,这些对象的类型就是PyObject:

1.1数据类型
Python定义了六种数据类型:整型、浮点型、字符串、元组、列表和字典,在使用C语言对Python进行功能扩展时,首先要了解如何在C和Python的数据类型间进行转化。
1.1.1 整型、浮点型和字符串
在Python的C语言扩展中要用到整型、浮点型和字符串这三种数据类型时相对比较简单,只需要知道如何生成和维护它们就可以了。下面的例子给出了如何在C语言中使用Python的这三种数据类型:
// build an integer
PyObject* pInt = Py_BuildValue("i", 2003);
assert(PyInt_Check(pInt));
int i = PyInt_AsLong(pInt);
Py_DECREF(pInt);
// build a float
PyObject* pFloat = Py_BuildValue("f", 3.14f);
assert(PyFloat_Check(pFloat));
float f = PyFloat_AsDouble(pFloat);
Py_DECREF(pFloat);
// build a string
PyObject* pString = Py_BuildValue("s", "Python");
assert(PyString_Check(pString);
int nLen = PyString_Size(pString);
char* s = PyString_AsString(pString);
Py_DECREF(pString);

1.1.2 元组
Python语言中的元组是一个长度固定的数组,当Python解释器调用C语言扩展中的方法时,所有非关键字(non-keyword)参数都以元组方式进行传递。下面的例子示范了如何在C语言中使用Python的元组类型:
// create the tuple
PyObject* pTuple = PyTuple_New(3);
assert(PyTuple_Check(pTuple));
assert(PyTuple_Size(pTuple) == 3);
// set the item
PyTuple_SetItem(pTuple, 0, Py_BuildValue("i", 2003));
PyTuple_SetItem(pTuple, 1, Py_BuildValue("f", 3.14f));
PyTuple_SetItem(pTuple, 2, Py_BuildValue("s", "Python"));
// parse tuple items
int i;
float f;
char *s;
if (!PyArg_ParseTuple(pTuple, "ifs", &i, &f, &s))
    PyErr_SetString(PyExc_TypeError, "invalid parameter");
// cleanup
Py_DECREF(pTuple);

1.1.3列表
Python语言中的列表是一个长度可变的数组,列表比元组更为灵活,使用列表可以对其存储的Python对象进行随机访问。下面的例子示范了如何在C语言中使用Python的列表类型:
// create the list
PyObject* pList = PyList_New(3); // new reference
assert(PyList_Check(pList));
// set some initial values
for(int i = 0; i < 3; ++i)
    PyList_SetItem(pList, i, Py_BuildValue("i", i));
// insert an item
PyList_Insert(pList, 2, Py_BuildValue("s", "inserted"));
// append an item
PyList_Append(pList, Py_BuildValue("s", "appended"));
// sort the list
PyList_Sort(pList);
// reverse the list
PyList_Reverse(pList);
// fetch and manipulate a list slice
PyObject* pSlice = PyList_GetSlice(pList, 2, 4); // new reference
for(int j = 0; j < PyList_Size(pSlice); ++j) {
  PyObject *pValue = PyList_GetItem(pList, j);
  assert(pValue);
}
Py_DECREF(pSlice);
// cleanup
Py_DECREF(pList);

1.1.4 字典
Python语言中的字典是一个根据关键字进行访问的数据类型。下面的例子示范了如何在C语言中使用Python的字典类型:
// create the dictionary
PyObject* pDict = PyDict_New(); // new reference
assert(PyDict_Check(pDict));
// add a few named values
PyDict_SetItemString(pDict, "first",
                     Py_BuildValue("i", 2003));
PyDict_SetItemString(pDict, "second",
                     Py_BuildValue("f", 3.14f));
// enumerate all named values
PyObject* pKeys = PyDict_Keys(); // new reference
for(int i = 0; i < PyList_Size(pKeys); ++i) {
  PyObject *pKey = PyList_GetItem(pKeys, i);
  PyObject *pValue = PyDict_GetItem(pDict, pKey);
  assert(pValue);
}
Py_DECREF(pKeys);
// remove a named value
PyDict_DelItemString(pDict, "second");
// cleanup
Py_DECREF(pDict);

2 接口文件
接口文件是一个c/c++文件,它由三部分构成
1.导出函数
2.方法列表
3.初始化函数
2.1 导出函数
要在Python解释器中使用c/c++语言中的某个函数,首先要为其编写相应的导出函数,在接口文件中,所有的导出函数都具有相同的函数原型:
PyObject* method(PyObject* self, PyObject* argvs);

该函数是Python解释器和C函数进行交互的接口,带有两个参数:self和args。参数self只在C函数被实现为内联方法(built- in method)时才被用到,通常该参数的值为空(NULL)。参数args中包含了Python解释器要传递给C函数的所有参数,通常使用Python的 C语言扩展接口提供的函数PyArg_ParseTuple()来获得这些参数值。
所有的导出函数都返回一个PyObject指针,如果对应的C函数没有真正的返回值(即返回值类型为void),则应返回一个全局的None对象(Py_None),并将其引用计数增1,如下所示:
PyObject* method(PyObject *self, PyObject *argvs)
{
  Py_INCREF(Py_None);
  return Py_None;
}

对于argvs通常会用PyArg_ParseTuple() 函数来;解析,其原型为:
int PyArg_ParseTuple(PyObject *arg, char *format, ...)
举些例子:
    int ok;
    int i, j;
    long k, l;
    char *s;
    int size;
    ok = PyArg_ParseTuple(args, ""); /* No arguments */
        /* Python call: f() */
    ok = PyArg_ParseTuple(args, "s", &s); /* A string */
        /* Possible Python call: f('whoops!') */
    ok = PyArg_ParseTuple(args, "lls", &k, &l, &s); /* Two longs and a string */
        /* Possible Python call: f(1, 2, 'three') */
    ok = PyArg_ParseTuple(args, "(ii)s#", &i, &j, &s, &size);
        /* A pair of ints and a string, whose size is also returned */
        /* Possible Python call: f((1, 2), 'three') */
    {
        char *file;
        char *mode = "r";
        int bufsize = 0;
        ok = PyArg_ParseTuple(args, "s|si", &file, &mode, &bufsize);
        /* A string, and optionally another string and an integer */
        /* Possible Python calls:
           f('spam')
           f('spam', 'w')
           f('spam', 'wb', 100000) */
    }
    {
        int left, top, right, bottom, h, v;
        ok = PyArg_ParseTuple(args, "((ii)(ii))(ii)",
                 &left, &top, &right, &bottom, &h, &v);
        /* A rectangle and a point */
        /* Possible Python call:
           f(((0, 0), (400, 300)), (10, 10)) */
    }
    {
        Py_complex c;
        ok = PyArg_ParseTuple(args, "D:myfunction", &c);
        /* a complex, also providing a function name for errors */
        /* Possible Python call: myfunction(1+2j) */
    }

2.2 方法列表
方法列表中给出了所有可以被Python解释器使用的方法,假设我们已经定义了一个导出函数 SampleMethod
则对应的方法列表为:
static PyMethodDef exampleMethods[] =
{
  {"method", SampleMethod, METH_VARARGS, "some comment"},
  {NULL, NULL}
};

其中method为python调用c/c++函数时用的名称,而不是我们在接口文件中定义的SampleMethod(),方法列表将定义的函数和调用名称对应起来。METH_VARARGS是参数传递方式,可选的两种方式是METH_VARARGS和METH_KEYWORDS,其中 METH_VARARGS是参数传递的标准形式,它通过Python的元组在Python解释器和C函数之间传递参数,若采用METH_KEYWORD方式,则Python解释器和C函数之间将通过Python的字典类型在两者之间进行参数传递。
2.3 初始化函数
所有的Python扩展模块都必须要有一个初始化函数,以便Python解释器能够对模块进行正确的初始化。Python解释器规定所有的初始化函数的函数名都必须以init开头,并加上模块的名字。对于模块example来说,则相应的初始化函数为:
DL_EXPORT(void) initexample()
{
  PyObject* m;
  m = Py_InitModule("example", exampleMethods);
}

如果为c++,则需要加extern "C" 关键字
extern "C"
{
  DL_EXPORT(void) initexample()
  {
    Py_InitModule("example", exampleMethods);
  }
}

下面给一个完整的接口文件的例子,修改相应的部分就能使用
//interface file for python, coded by jumbo 2005.7.25
#include <python2.4/Python.h>
#include "emmanager.h"
// Add two arbitrary objects
static PyObject *emulator_calc(PyObject *pSelf, PyObject *pArgs)
{
  int routenum, wavenum, buffernum, bufferstorage,prio_algo,;
    char *servtype;
    char *wcenable;
    char *servprio;
    float speed,load,rsvbuf;
    if (!PyArg_ParseTuple(pArgs,"iiisfifssif", &routenum, &wavenum,&buffernum,&servtype,&speed,&bufferstorage,&load,&wcenable,&servprio,&prio_algo,&rsvbuf))
      return NULL;
    try
      {
 EmManager::GetManager()->Run(routenum, wavenum,buffernum,servtype,speed,bufferstorage,load,wcenable,servprio,prio_algo,rsvbuf);   
      }
    catch(Err &a)
      {
 cout<<"a.GetErr()"<<endl;
      }
    Py_INCREF(Py_None);
    return Py_None;
}
static PyObject *emulator_getlostrateall(PyObject *pSelf, PyObject *pArgs)
{
  if (!PyArg_ParseTuple(pArgs,""))
    {
      return NULL;
    }
  float lostrate = EmManager::GetManager()->GetLostRateAll();
  return Py_BuildValue("f",lostrate);
}

static PyObject *emulator_getlostratebesteffort(PyObject *pSelf, PyObject *pArgs)
{
  if (!PyArg_ParseTuple(pArgs,""))
    {
      return NULL;
    }
  float lostrate = EmManager::GetManager()->GetLostRateBestEffort();
  return Py_BuildValue("f",lostrate);
}
static PyObject *emulator_getlostratelowloss(PyObject *pSelf, PyObject *pArgs)
{
  if (!PyArg_ParseTuple(pArgs,""))
    {
      return NULL;
    }
  float lostrate = EmManager::GetManager()->GetLostRateLowLoss();
  return Py_BuildValue("f",lostrate);
}
// Map of function names to functions
static PyMethodDef emulator_method[] =
{
  {"Calc",emulator_calc, METH_VARARGS, "Calculate the loss probility of optical XC"},
  {"GetLostRateAll",emulator_getlostrateall, METH_VARARGS, "Get the lost rate for all packages"},
  {"GetLostRateLowLoss",emulator_getlostratelowloss, METH_VARARGS, "Get the lost rate for low loss packages"},
  {"GetLostRateBestEffort",emulator_getlostratebesteffort, METH_VARARGS, "Get the lost rate for best effort packages"},
  {NULL, NULL} // End of functions
};
// For C++,  should  declared extern "C"
extern "C"
{
  DL_EXPORT(void) initemulator()
  {
    Py_InitModule("emulator", emulator_method);
  }
}

3 编译发布
本文只讨论Linux下的编译和发布方法,windows下需要使用VC6编译dll文件,暂不讨论。
1 直接编译
在文件数目较少的情况下直接编译很方便,使用gcc或者g++,加share参数:
gcc -fpic -c interface.c -o example.o
gcc -fpic -c realcode.c -o realcode.o
gcc -shared -o example.so example.o realcode.o
2 编写setup.py
使用python自带的utilitis工具很容易将我们刚才编写的接口文件和c/c++源代码编译为python可
使用的动态共享文件,通常是以*.so结尾。
from distutils.core import setup, Extension
module1 = Extension('emulator',
                    define_macros = [('MAJOR_VERSION', '1'),
                                     ('MINOR_VERSION', '0')],
                    include_dirs = ['/usr/include'],
                    libraries = ['gsl','gslcblas'],
                    library_dirs = ['/usr/lib'],
                    sources = ['moduleem.cpp', 'process.cpp', 'emulator.cpp','random.cpp','prio.cpp','emmanager.cpp'])
setup (name = 'emulator',
       version = '1.0',
       description = 'This is a alpha package',
       author = 'jumbo',
       author_email = 'jumbon@hotmail.com',
       url = 'http://www.python.org/doc/current/ext/building.html',
       long_description = '''
This is really just a demo package.
''',
       ext_modules = [module1])

上述是一个demo的setup文件,只需要修改相应的地方就能使用,其中source源不需要写h文件。具体的
请参考disutils的说明文档。
然后编译就能使用了
python setup.py build
将生成的*.so文件直接拷贝到python文件可以找的地方,比如当前python文件目录或者/usr/lib , /usr/local/lib
4 引用
直接import刚才生成的文件就可以使用接口文件的函数了:
from example import *

参考:
本文参考了肖文鹏的《用C语言扩展Python的功能》,地址在:
[url]http://www-128.ibm.com/developerworks/cn/linux/l-pythc/index.html
以及python网站关于extending and embedding the Python Interpreter的文章,地址在:
[url]http://www.python.org/doc/2.0.1/ext/ext.html

skip for python

Python Performance Tips

This page is devoted to various tips and tricks that help improve the performance of your Python programs. Wherever the information comes from someone else, I've tried to identify the source.

If you have any light to shed on this subject, let me know.

Contents
Profiling Code
Profile Module
Trace Module
Sorting
String concatenation
Loops
Avoiding dots...
Local Variables
Initializing Dictionary Elements
Import Statement Overhead
Using map with Dictionaries
Data Aggregation
Doing Stuff Less Often
Profiling Code
The first step to speeding up your program is learning where the bottlenecks lie. It hardly makes sense to optimize code that is never executed or that already runs fast. I use two modules to help locate the hotspots in my code, profile and trace.

Profile Module
The profile module is included as a standard module in the Python distribution. Using it to profile the execution of a set of functions is quite easy. Suppose your main function is called main, takes no arguments and you want to execute it under the control of the profile module. In its simplest form you just execute

import profile
profile.run('main()')

When main() returns, the profile module will print a table of function calls and execution times. The output can be tweeked using the Stats class included with the module. For more details, check out the profile module's documentation (Lib/profile.doc).
Trace Module
The trace module is a spin-off of the profile module I wrote originally to perform some crude statement level test coverage. As of Python 2.0 you should find trace.py in the Tools/scripts directory of the Python distribution. Thanks to Andrew Dalke it's very easy to run from the command line to trace execution of whole scripts:

% trace.py -t spam.py eggs

There's no separate documentation, but there are some pretty complete docstrings at the top of the module.
Sorting
From Guido van Rossum

Sorting lists of basic Python objects is generally pretty efficient. The sort method for lists takes an optional comparison function as an argument that can be used to change the sorting behavior. This is quite convenient, though it can really slow down your sorts.

An alternative way to speed up sorts is to construct a list of tuples whose first element is a sort key that will sort properly using the default comparison, and whose second element is the original list element.

Suppose, for example, you have a list of tuples that you want to sort by the n-th field of each tuple. The following function will do that.

def sortby(list, n):
nlist = map(lambda x, n=n: (x[n], x), list)
nlist.sort()
return map(lambda (key, x): x, nlist)

Here's an example use:
>>> list = [(1, 2, 'def'), (2, -4, 'ghi'), (3, 6, 'abc')]
>>> list.sort()
>>> list
[(1, 2, 'def'), (2, -4, 'ghi'), (3, 6, 'abc')]
>>> sortby(list, 2)
[(3, 6, 'abc'), (1, 2, 'def'), (2, -4, 'ghi')]
>>> sortby(list, 1)
[(2, -4, 'ghi'), (1, 2, 'def'), (3, 6, 'abc')]

String Concatenation
Strings in Python are immutable. This fact frequently sneaks up and bites novice Python programmers on the rump. Immutability confers some advantages and disadvantages. In the plus column, strings can be used a keys in dictionaries and individual copies can be shared among multiple variable bindings. (Python automatically shares one- and two-character strings.) In the minus column, you can't say something like, "change all the 'a's to 'b's" in any given string. Instead, you have to create a new string with the desired properties. This continual copying can lead to significant inefficiencies in Python programs.

The following is adapted from inputs by Aaron Watters:

Avoid this:

str = ""
for substring in list:
str = str + substring

Use "".join(list) instead. The former is a very common and catastrophic mistake when building large strings. Similarly, if you are generating bits of a string sequentially instead of

str = ""
for x list:
str = str + some_function(x)

use
str = [None]*len(list):
for x in range(len(list):
str[x] = some_function(list[x])
str = "".join(str)

Avoid:

out = "" + head + prologue + query + tail + "

Instead, use
out = "%s%s%s%s" % (head, prologue, query, tail)

This is a lot faster, and easier to modify also. In addition, the slow way of doing things got slower in Python 2.0 with the addition of rich comparisons to the language. It now takes the Python virtual machine a lot longer to figure out how to concatenate to strings. (Don't forget that Python does all method lookup at runtime.)

Loops
Python supports a couple of looping constructs. The for statement is most commonly used. It loops over the elements of a sequence, assigning each to the loop variable. If the body of your loop is simple, the interpreter overhead of the for loop itself can be a substantial amount of the overhead. This is where the map function is handy. You can think of map as a for moved into C code. The only restriction is that the "loop body" of map must be a function call.

Here's a straightforward example. Instead of looping over a list of words and converting them to upper case:

newlist = []
for word in list:
newlist.append(word.upper())

you can use map to push the loop from the interpreter into compiled C code:
import string
newlist = map(string.upper, list)

List comprehensions were added to Python in version 2.0 as well. They provide a syntactically more compact way of writing the above for loop:

newlist = [s.upper() for s in list]

It's not really any faster than the for loop version, however.
Guido van Rossum wrote a much more detailed examination of loop optimization that is definitely worth reading.

Avoiding dots...
Suppose you can't use map? The example above of converting words in a list to upper case has another inefficiency. Both newlist.append and string.upper are function references that are recalculated each time through the loop. The original loop can be replaced with:
import string
upper = string.upper
newlist = []
append = newlist.append
for word in list:
append(upper(word))

Local Variables
The final speedup available to us for the non-map version of the for loop is to use local variables wherever possible. If the above loop is cast as a function, append and upper become local variables.

def func():
upper = string.upper
newlist = []
append = newlist.append
for word in words:
append(upper(word))
return newlist

An extra performance boost is received because local variables are accessed more efficiently than variables at module scope. On my machine (100MHz Pentium running BSDI), I got the following times for converting the list of words in /usr/share/dict/words (38,470 words) to upper case:

Version Time (seconds)
Basic loop 3.47
Eliminate dots 2.45
Local variable & no dots 1.79
Using map function 0.54

Eliminating the loop overhead by using map is often going to be the most efficient option. When the complexity of your loop precludes its use other techniques are available to speed up your loops, however.

Initializing Dictionary Elements
Suppose you are building a dictionary of word frequencies and you've already broken your words up into a list. You might execute something like:

wdict = {}
for word in words:
if not wdict.has_key(word): wdict[word] = 0
wdict[word] = wdict[word] + 1

Except for the first time, each time a word is seen the if statement's test fails. If you are counting a large number of words, many will probably occur multiple times. In a situation where the initialization of a value is only going to occur once and the augmentation of that value will occur many times it is cheaper to use a try statement:

wdict = {}
for word in words:
try:
wdict[word] = wdict[word] + 1
except KeyError:
wdict[word] = 1

It's important to catch the expected exception, and not have a default except clause to avoid trying to recover from an exception you really can't handle by the statement(s) in the try clause.

Note that if the try clause generates an exception most of the time, it will often be more efficient to test for the exceptional condition than to generate it and recover from it.

Import Statement Overhead
import statements can be executed just about anywhere. It's often useful to place them inside functions to restrict their visibility and/or reduce initial startup time. Although Python's interpreter is optimized to not import the same module multiple times, repeatedly executing an import statement can seriously affect performance in some circumstances.

Consider the following two snippets of code (originally from Greg McFarlane, I believe - I found it unattributed in a comp.lang.python/python-list@python.org posting and later attributed to him in another source):

def doit():
import string ###### import statement inside function
string.lower('Python')

for num in range(100000):
doit()

or:
import string ###### import statement outside function
def doit():
string.lower('Python')

for num in range(100000):
doit()

The second version will run substantially faster than the first, even though the reference to the string module is global in the second example. String methods were introduced to the language in Python 2.0. These provide a version that avoids import completely:
def doit():
'Python'.lower()

for num in range(100000):
doit()

The above example is obviously a bit contrived, but the general principle holds.

Using map with Dictionaries
I found it frustrating that to use map to eliminate simple for loops like:

dict = {}
nil = []
for x in list:
dict[x] = nil

I had to use a lambda form or define a named function that would probably negate any speedup I was getting by using map in the first place. I decided I needed some functions to allow me to set, get or delete dictionary keys and values en masse. I proposed a change to Python's dictionary object and used it for awhile. However, a more general solution appears in the form of the operator module in Python 1.4. Suppose you have a list and you want to eliminate its duplicates. Instead of the code above, you can execute:
dict = {}
map(operator.setitem, [dict]*len(list), list, [])
list = statedict.keys()

This moves the for loop into C where it executes much faster.
Data Aggregation
(Paraphrased from a note by Aaron Watters)

Function call overhead in Python is relatively high, especially compared with the execution speed of a builtin function. This strongly suggests that extension module functions should handle aggregates of data where possible. Here's a contrived example written in Python. (Just pretend the function was written in C. :-)

x = 0
def doit(i):
global x
x = x + i

list = range(10000)
for i in list:
doit(i)

vs.
x = 0
def doit(list):
global x
for i in list:
x = x + i

list = range(10000)
doit(list)

Even written in Python, the second example runs about four times faster than the first. Had doit been written in C the difference would likely have been even greater (exchanging a Python for loop for a C for loop as well as removing most of the function calls).
Doing Stuff Less Often
The Python interpreter performs some periodic checks. In particular, it decides whether or not to let another thread run and whether or not to run a pending call (typically a call established by a signal handler). Most of the time there's nothing to do, so performing these checks each pass around the interpreter loop can slow things down. There is a function in the sys module, setcheckinterval, which you can call to tell the interpreter how often to perform these periodic checks. In Python 1.4 it defaults to 10. If you aren't running with threads and you don't expect to be catching lots of signals, setting this to a larger value can improve the interpreter's performance, sometimes substantially.
January 2010
S M T W T F S
December 2009February 2010
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30