2009/12/15

PyGTK下编写多线程程序

没有评论:
虽然在PyGTK中Python有关多线程的库(thread,threading)可以使用,但其行为常现异常,所以一定要按照PyGTK的要求编写多线程应用程序。

How threads works in pygtk using the threading module?

Threads are a way for a program to split itself into two or more simultaneously running tasks. The way that we create threads in python is writing subclasses of the threading.Thread class, the method run, should be overloaded so we include there the code that we want to be rant on each thread.

In order to create a new thread, we should create a new Thread object and then, call the start method which creates the new thread, and executes the run method in its context.

The problem with PyGTK is that the gtk.main() loop won't refresh the screen each time that the fraction is set, we need to use the gtk thread engine. We need to call the gtk.thread_init() function to start the thread engine, this call should be made on the same thread that the gtk.main() function is called. In fact, calling it right afer importing the gtk module is a good practice.

Thus, we should use gtk.threads_enter() before any access to gtk object, and, once we end up doing transformations, we should call gtk.threads_leave().

We should call to the stop method in the exit callback so when the window is closed the application ends the thread and the script doesn't hangs.

只允許主線程修改圖形界面

這是較常用的一種方式,但編寫時略顯複雜。首先,在程序初始化時調用(一定在gtk.main()之前運行):
gobject.threads_init()
多線程的實現方式與純Python相同:
t=threading.Thread(target=新线程的函数)
t.start()
要修改界面的代碼則使用gobject.idle_add加到GTK的主循環中。
gobject.idle_add(新线程函数, 参数)
注意如果新線程函數返回True,則該函數仍在GTK的主循環中,如果返回False,則退出主循環。下面的例子是PyGTK.org上給出的:
import threading
import time
import gobject
import gtk

gobject.threads_init()

class MyThread(threading.Thread):
 def __init__(self, label):
     super(MyThread, self).__init__()
     self.label = label
     self.quit = False

 def update_label(self, counter):
     self.label.set_text("Counter: %i" % counter)
     return False

 def run(self):
     counter = 0
     while not self.quit:
         counter += 1
         gobject.idle_add(self.update_label, counter)
         time.sleep(0.1)

w = gtk.Window()
l = gtk.Label()
w.add(l)
w.show_all()
w.connect("destroy", lambda _: gtk.main_quit())
t = MyThread(l)
t.start()

gtk.main()
t.quit = True

允許所有線程修改圖形界面

這種方法要簡單很多。與前面類似,在程序初始化時調用:
gtk.gdk.threads_init()
不過要把gtk.main()用下面兩個函數括起來:
gtk.threads_enter()
gtk.main()
gtk.threads_leave()
其它線程也是如此,在修改界面內容的代碼前後加上
gtk.threads_enter()
...
gtk.threads_leave()

The following example shows how to do it using a random fraction for the progress bar:

import threading
import random, time
import gtk
#Initializing the gtk's thread engine
gtk.threads_init()


class FractionSetter(threading.Thread):
 """This class sets the fraction of the progressbar"""

#Thread event, stops the thread if it is set.
stopthread = threading.Event()

def run(self):
  """Run method, this is the code that runs while thread is alive."""

 #Importing the progressbar widget from the global scope
 global progressbar

 #While the stopthread event isn't setted, the thread keeps going on
 while not self.stopthread.isSet() :
  # Acquiring the gtk global mutex
  gtk.threads_enter()
  #Setting a random value for the fraction
  progressbar.set_fraction(random.random())
  # Releasing the gtk global mutex
  gtk.threads_leave()
 
  #Delaying 100ms until the next iteration
  time.sleep(0.1)
 
def stop(self):
  """Stop method, sets the event to terminate the thread's main loop"""
 self.stopthread.set()

def main_quit(obj):
 """main_quit function, it stops the thread and the gtk's main loop"""
#Importing the fs object from the global scope
global fs
#Stopping the thread and the gtk's main loop
fs.stop()
gtk.main_quit()

#Gui bootstrap: window and progressbar
window = gtk.Window()
progressbar = gtk.ProgressBar()
window.add(progressbar)
window.show_all()
#Connecting the 'destroy' event to the main_quit function
window.connect('destroy', main_quit)

#Creating and starting the thread
fs = FractionSetter()
fs.start()

gtk.main()

Refer to:
http://aruiz.typepad.com/siliconisland/2006/04/threads_on_pygt.html
http://docs.python.org/library/threading.html

2009/11/29

Ubuntu下的PDF编辑工具

没有评论:
Pdftk是由Sid Steward写的一个PDF增强软件,也就是所谓的PDF Hacks。它可以合并/分割PDF文档、解开必要的输入密码、输出加密、给PDF文档加水印、从PDF文档中解出附件、将PDF文档变成一页等等,能够做到操作PDF文档的所有事情。

安装:
sudo apt-get install pdftk


其合并文档的具体用法为:

按照顺序合并多个文档成一个文档:
pdftk 1.pdf 2.pdf 3.pdf cat output 123.pdf

使用参数:
pdftk A=1.pdf B=2.pdf cat A B output 12.pdf

使用通配符:
pdftk *.pdf cat output combined.pdf

从几个文档中分割内容合并成一个文档:
pdftk A=one.pdf B=two.pdf cat A1-7 B1-5 A8 output combined.pdf

或者 (使用通配符):
pdftk *.pdf cat output combined.pdf

把多个PDF的不同页面组合成一个新的PDF文档
pdftk A=one.pdf B=two.pdf cat A1-7 B1-5 A8 output combined.pdf

旋转PDF第一页90度
pdftk in.pdf cat 1E 2-end output out.pdf

选择所有PDF页面180度:
pdftk in.pdf cat 1-endS output out.pdf

使用128强度加密PDF
pdftk mydoc.pdf output mydoc.128.pdf owner_pw foopass

同上,同时给PDF加上访问密码
pdftk mydoc.pdf output mydoc.128.pdf owner_pw foo user_pw baz

同上,但是运行打印:
pdftk mydoc.pdf output mydoc.128.pdf owner_pw foo user_pw baz allow printing

解密PDF文档:
pdftk secured.pdf input_pw foopass output unsecured.pdf

合并两个PDF文档,其中一个是加密的,但最终文档不加密:
pdftk A=secured.pdf mydoc.pdf input_pw A=foopass cat output combined.pdf

解压PDF流,以便文本编辑:
pdftk mydoc.pdf output mydoc.clear.pdf uncompress

修复PDF文档
pdftk broken.pdf output fixed.pdf

分解成单页
pdftk mydoc.pdf burst

报告PDF信息,输出到文本
pdftk mydoc.pdf dump_data output report.txt


Pdfedit

PDFedit可以让你整个的编辑PDF文档。你可以改变PDF的任意部分。功能可以使用脚本添加。
脚本可以使用其他外部编辑器,并且可以定制自己的脚本。

安装
sudo apt-get install pdfedit


GIMP

首先安装krita:
sudo apt-get install krita

打开GIMP,然后打开PDF文件。对于多页文件,编辑也非常容易,它会自动打开多个编辑窗口。编辑完成以后,存为XCF格式。用krita打开XCF文件,选择“File"->"Printe",选择打印成PDF文件,并且选择目标文件的保持位置。


pdfjam
pdf合并和分拆工具.
下载:http://umn.dl.sourceforge.net/sourceforge/pdfsam/pdfsam-0.7sr1-out.zip(使用basic版,加强版收费)

2009/11/07

Ubuntu: 自动登录无线网络

没有评论:
ubuntu 自动登录无线网络

每次登录后连接无线网络时,总提示 nm-applet "enter password for default keyring to unlock". 因为笔记本就一个人用,这个提示很烦人,即使密码设成和login密码一样也无济于事。

解决办法: 给 keyring manager 设置一个空密码。
Menu->Applications->Accessories->Password and Encryption keys-> Passwords Tab -> Passwords:login 点右键, Unlock and then change password to blank。虽然会有安全提示,不管它,选 "Use unsafe storage",OK


Refer to:
Auto-Unlock Keyring Manager In Ubuntu

2009/11/04

Ubuntu 9.10 中文输入法

没有评论:
Ubuntu 9.10 中文输入法


9.10自带的是ibus,到menu->system->preference->ibus preference中加入 “拼Chinese-PinYin"输入法,同时删掉"English-ispell",即只保留一个即可。最后需要重启。按"ctrl+space" to turn off 输入法。


scim 程序有,但以前集成的输入法在9.10中缺。如需要,可
sudo apt-get install scim
打开新立得软件管理器(Synaptic),单击“搜索”按钮,输入scim,搜索与SCIM相关得所有软件。找到pinyin模块,单击右键,选择“标记并安装”项,单击“应用”按钮。打开SCIM配置实用工具对相关选项进行配置,重启计算机。


建议: 以后不能当ubuntu early adopter,因为总有一些bug让人担心。比如Ubuntu 9.10 中input/output error的突然出现让我虚惊一场:以为自己的文件会丢失,虽然重启后恢复正常。

2009/07/29

如何调用DLL (基于Visual C++6.0的DLL)

没有评论:
一、前言

  自从微软推出16位的Windows操作系统起,此后每 种版本的Windows操作系统都非常依赖于动态链接库(DLL)中的函数和数据,实际上Windows操作系统中几乎所有的内容都由DLL以一种或另外 一种形式代表着,例如显示的字体和图标存储在GDI DLL中、显示Windows桌面和处理用户的输入所需要的代码被存储在一个User DLL中、Windows编程所需要的大量的API函数也被包含在Kernel DLL中。

  在Windows操作系统中使用 DLL有很多优点,最主要的一点是多个应用程序、甚至是不同语言编写的应用程序可以共享一个DLL文件,真正实现了资源"共享",大大缩小了应用程序的执 行代码,更加有效的利用了内存;使用DLL的另一个优点是DLL文件作为一个单独的程序模块,封装性、独立性好,在软件需要升级的时候,开发人员只需要修 改相应的DLL文件就可以了,而且,当DLL中的函数改变后,只要不是参数的改变,程序代码并不需要重新编译。这在编程时十分有用,大大提高了软件开发和 维护的效率。

  既然DLL那么重要,所以搞清楚什么是DLL、如何在Windows操作系统中开发使用DLL是程序开发人员不得不 解决的一个问题。本文针对这些问题,通过一个简单的例子,即在一个DLL中实现比较最大、最小整数这两个简单函数,全面地解析了在Visual C++编译环境下编程实现DLL的过程,文章中所用到的程序代码在Windows98系统、Visual C++6.0编译环境下通过。

  二、DLL的概念

   DLL是建立在客户/服务器通信的概念上,包含若干函数、类或资源的库文件,函数和数据被存储在一个DLL(服务器)上并由一个或多个客户导出而使用, 这些客户可以是应用程序或者是其它的DLL。DLL库不同于静态库,在静态库情况下,函数和数据被编译进一个二进制文件(通常扩展名 为*.LIB),Visual C++的编译器在处理程序代码时将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为"静态链接",此 时因为应用程序所需的全部内容都是从库中复制了出来,所以静态库本身并不需要与可执行文件一起发行。

  在动态库的情况下,有两个文 件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB 文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中 所要调用的函数的内存地址,这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL 和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。

  微软的Visual C++支持三种DLL,它们分别是Non-MFC Dll(非MFC动态库)、Regular Dll(常规DLL)、Extension Dll(扩展DLL)。Non-MFC DLL指的是不用MFC的类库结构,直接用C语言写的DLL,其导出的函数是标准的C接口,能被非MFC或MFC编写的应用程序所调用。Regular DLL:和下述的Extension Dlls一样,是用MFC类库编写的,它的一个明显的特点是在源文件里有一个继承CWinApp的类(注意:此类DLL虽然从CWinApp派生,但没有 消息循环),被导出的函数是C函数、C++类或者C++成员函数(注意不要把术语C++类与MFC的微软基础C++类相混淆),调用常规DLL的应用程序 不必是MFC应用程序,只要是能调用类C函数的应用程序就可以,它们可以是在Visual C++、Dephi、Visual Basic、Borland C等编译环境下利用DLL开发应用程序。

  常规DLL又可细分成静态链接到MFC和动态链接到MFC上的,这两种常规DLL的区别将在下面介绍。与常规DLL相比,使用扩展DLL用于导出增强MFC基础类的函数或子类,用这种类型的动态链接库,可以用来输出一个从MFC所继承下来的类。

   扩展DLL是使用MFC的动态链接版本所创建的,并且它只被用MFC类库所编写的应用程序所调用。例如你已经创建了一个从MFC的CtoolBar类的 派生类用于创建一个新的工具栏,为了导出这个类,你必须把它放到一个MFC扩展的DLL中。扩展DLL 和常规DLL不一样,它没有一个从CWinApp继承而来的类的对象,所以,开发人员必须在DLL中的DllMain函数添加初始化代码和结束代码。

三、动态链接库的创建

   在Visual C++6.0开发环境下,打开FileNewProject选项,可以选择Win32 Dynamic-Link Library或MFC AppWizard[dll]来以不同的方式来创建Non-MFC Dll、Regular Dll、Extension Dll等不同种类的动态链接库。

  1. Win32 Dynamic-Link Library方式创建Non-MFC DLL动态链接库

   每一个DLL必须有一个入口点,这就象我们用C编写的应用程序一样,必须有一个WINMAIN函数一样。在Non-MFC DLL中DllMain是一个缺省的入口函数,你不需要编写自己的DLL入口函数,用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。如果 应用程序的DLL需要分配额外的内存或资源时,或者说需要对每个进程或线程初始化和清除操作时,需要在相应的DLL工程的.CPP文件中对 DllMain()函数按照下面的格式书写。
 

 

BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
.......
case DLL_THREAD_ATTACH:
.......
case DLL_THREAD_DETACH:
.......
case DLL_PROCESS_DETACH:
.......
}
return TRUE;
}

   参数中,hMoudle是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择 符);ul_reason_for_call是一个说明动态库被调原因的标志,当进程或线程装入或卸载动态链接库的时候,操作系统调用入口函数,并说明动 态链接库被调用的原因,它所有的可能值为:DLL_PROCESS_ATTACH: 进程被调用、DLL_THREAD_ATTACH: 线程被调用、DLL_PROCESS_DETACH: 进程被停止、DLL_THREAD_DETACH: 线程被停止;lpReserved为保留参数。到此为止,DLL的入口函数已经写了,剩下部分的实现也不难,你可以在DLL工程中加入你所想要输出的函数 或变量了。

  我们已经知道DLL是包含若干个函数的库文件,应用程序使用DLL中的函数之前,应该先导出这些函数,以便供给应用程 序使用。要导出这些函数有两种方法,一是在定义函数时使用导出关键字_declspec(dllexport),另外一种方法是在创建DLL文件时使用模 块定义文件.Def。需要读者注意的是在使用第一种方法的时候,不能使用DEF文件。下面通过两个例子来说明如何使用这两种方法创建DLL文件。

  1)使用导出函数关键字_declspec(dllexport)创建MyDll.dll,该动态链接库中有两个函数,分别用来实现得到两个数的最大和最小数。在MyDll.h和MyDLL.cpp文件中分别输入如下原代码:
 

//MyDLL.h
extern "C" _declspec(dllexport) int Max(int a, int b);
extern "C" _declspec(dllexport) int Min(int a, int b);
//MyDll.cpp
#i nclude
#i nclude"MyDll.h"
int Max(int a, int b)
{
if(a>=b)return a;
else
return b;
}
int Min(int a, int b)
{
if(a>=b)return b;
else
return a;
}

   该动态链接库编译成功后,打开MyDll工程中的debug目录,可以看到MyDll.dll、MyDll.lib两个文件。LIB文件中包含DLL文 件名和DLL文件中的函数名等,该LIB文件只是对应该DLL文件的"映像文件",与DLL文件中,LIB文件的长度要小的多,在进行隐式链接DLL时要 用到它。读者可能已经注意到在MyDll.h中有关键字"extern C",它可以使其他编程语言访问你编写的DLL中的函数。

  2)用.def文件创建工程MyDll

  为了用.def文件创建DLL,请先删除上个例子创建的工程中的MyDll.h文件,保留MyDll.cpp并在该文件头删除#i nclude MyDll.h语句,同时往该工程中加入一个文本文件,命名为MyDll.def,再在该文件中加入如下代码:

LIBRARY MyDll
EXPORTS
Max
Min

   其中LIBRARY语句说明该def文件是属于相应DLL的,EXPORTS语句下列出要导出的函数名称。我们可以在.def文件中的导出函数后加 @n,如Max@1,Min@2,表示要导出的函数顺序号,在进行显式连时可以用到它。该DLL编译成功后,打开工程中的Debug目录,同样也会看到 MyDll.dll和MyDll.lib文件。

  2.MFC AppWizard[dll]方式生成常规/扩展DLL

   在MFC AppWizard[dll]下生成DLL文件又有三种方式,在创建DLL是,要根据实际情况选择创建DLL的方式。一种是常规DLL静态链接到MFC, 另一种是常规DLL动态链接到MFC。两者的区别是:前者使用的是MFC的静态链接库,生成的DLL文件长度大,一般不使用这种方式,后者使用MFC的动 态链接库,生成的DLL文件长度小;动态链接到MFC的规则DLL所有输出的函数应该以如下语句开始:
 

AFX_MANAGE_STATE(AfxGetStaticModuleState( )) //此语句用来正确地切换MFC模块状态

   最后一种是MFC扩展DLL,这种DLL特点是用来建立MFC的派生类,Dll只被用MFC类库所编写的应用程序所调用。前面我们已经介绍 过,Extension DLLs 和Regular DLLs不一样,它没有一个从CWinApp继承而来的类的对象,编译器默认了一个DLL入口函数DLLMain()作为对DLL的初始化,你可以在此函 数中实现初始化,代码如下:
 

BOOL WINAPI APIENTRY DLLMain(HINSTANCE hinstDll,DWORD reason ,LPVOID flmpload)
{
switch(reason)
{
……………//初始化代码;
}
return true;
}

  参数hinstDll存放DLL的句柄,参数reason指明调用函数的原因,lpReserved是一个被系统所保留的参数。对于隐式链接是一个非零值,对于显式链接值是零。

   在MFC下建立DLL文件,会自动生成def文件框架,其它与建立传统的Non-MFC DLL没有什么区别,只要在相应的头文件写入关键字_declspec(dllexport)函数类型和函数名等,或在生成的def文件中EXPORTS 下输入函数名就可以了。需要注意的是在向其它开发人员分发MFC扩展DLL 时,不要忘记提供描述DLL中类的头文件以及相应的.LIB文件和DLL本身,此后开发人员就能充分利用你开发的扩展DLL了。

四、动态链接库DLL的链接

   应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接。在使用DLL之前首先要知道DLL中函数的结构信息。Visual C++6.0在VC in目录下提供了一个名为Dumpbin.exe的小程序,用它可以查看DLL文件中的函数结构。另外,Windows系统将遵循下 面的搜索顺序来定位DLL: 1.包含EXE文件的目录,2.进程的当前工作目录, 3.Windows系统目录, 4.Windows目录,5.列在Path环境变量中的一系列目录。

  1.隐式链接

  隐式链接就是在程序开始 执行时就将DLL文件加载到应用程序当中。实现隐式链接很容易,只要将导入函数关键字_declspec(dllimport)函数名等写到应用程序相应 的头文件中就可以了。下面的例子通过隐式链接调用MyDll.dll库中的Min函数。首先生成一个项目为TestDll,在DllTest.h、 DllTest.cpp文件中分别输入如下代码:
 

 

//Dlltest.h
#pragma comment(lib,"MyDll.lib")
extern "C"_declspec(dllimport) int Max(int a,int b);
extern "C"_declspec(dllimport) int Min(int a,int b);
//TestDll.cpp
#i nclude
#i nclude"Dlltest.h"
void main()
{int a;
a=min(8,10)
printf("比较的结果为%d ",a);
}
 

   在创建DllTest.exe文件之前,要先将MyDll.dll和MyDll.lib拷贝到当前工程所在的目录下面,也可以拷贝到windows的 System目录下。如果DLL使用的是def文件,要删除TestDll.h文件中关键字extern "C"。TestDll.h文件中的关键字Progam commit是要Visual C+的编译器在link时,链接到MyDll.lib文件,当然,开发人员也可以不使用#pragma comment(lib,"MyDll.lib")语句,而直接在工程的Setting->Link页的Object/Moduls栏填入 MyDll.lib既可。

  2.显式链接

  显式链接是应用程序在执行过程中随时可以加载DLL文件,也可以随 时卸载DLL文件,这是隐式链接所无法作到的,所以显式链接具有更好的灵活性,对于解释性语言更为合适。不过实现显式链接要麻烦一些。在应用程序中用 LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态链接库调进来,动态链接库的文件名即是上述两个函数的参数,此 后再用GetProcAddress()获取想要引入的函数。自此,你就可以象使用如同在应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之 前,应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态链接库。下面是通过显式链接调用DLL中的Max函数的例子。
 

#i nclude
#i nclude
void main(void)
{
typedef int(*pMax)(int a,int b);
typedef int(*pMin)(int a,int b);
HINSTANCE hDLL;
PMax Max
HDLL=LoadLibrary("MyDll.dll");//加载动态链接库MyDll.dll文件;
Max=(pMax)GetProcAddress(hDLL,"Max");
A=Max(5,8);
Printf("比较的结果为%d ",a);
FreeLibrary(hDLL);//卸载MyDll.dll文件;
}

   在上例中使用类型定义关键字typedef,定义指向和DLL中相同的函数原型指针,然后通过LoadLibray()将DLL加载到当前的应用程序中 并返回当前DLL文件的句柄,然后通过GetProcAddress()函数获取导入到应用程序中的函数指针,函数调用完毕后,使用 FreeLibrary()卸载DLL文件。在编译程序之前,首先要将DLL文件拷贝到工程所在的目录或Windows系统目录下。

   使用显式链接应用程序编译时不需要使用相应的Lib文件。另外,使用GetProcAddress()函数时,可以利用 MAKEINTRESOURCE()函数直接使用DLL中函数出现的顺序号,如将GetProcAddress(hDLL,"Min")改为 GetProcAddress(hDLL, MAKEINTRESOURCE(2))(函数Min()在DLL中的顺序号是2),这样调用DLL中的函数速度很快,但是要记住函数的使用序号,否则会 发生错误。

2009/07/12

python: handle exceptions

没有评论:
try:
# code here
except Exception, err:
sys.stderr.write('ERROR: %s\n' % str(err))
import traceback
traceback.print_exc()
else:
# normal
finally:
###


Refer:
Python Exception Handling Techniques

traceback — Print or retrieve a stack traceback

2009/06/30

Linux下用smbmount命令挂载Windows共享

没有评论:
在Windows操作系统之间,可以通过映射网络驱动器的方式,将某个共享目录映射成一个磁盘文件系统,在Linux下,可以通过smbmount命令来实现相似的功能,将Windows的某个共享目录挂载到Linux下的某个目录下。

Note: ubuntu GUI下的"connect to server"并未真正mount windows shared filesystem, so can not see any mounted directory in terminal.

Let's manually mount a windows share thru commands!


1. Install smbmount

sudo apt-get install smbfs


2. Create a mount point "~/Desktop/winxp" in Ubuntu

fanghui@vbox:~/Desktop$ mkdir winxp # 必须先创建目录 winxp


3. smbmount command.

语法:smbmount //IP地址/共享名 挂载点 -o username=xxx,password=yyy
For example:
挂载整个c$共享
$ sudo smbmount //155.69.148.204/c$ ~/Desktop/winxp -o username=xxx
Password:

挂载某个目录"fanghui"
$ sudo smbmount //155.69.148.204/fanghui ~/Desktop/winxp -o username=xxx,password=xxxxxx


现在用mount查看,会看到最末一行:
//155.69.148.204/fanghui on /home/fanghui/Desktop/winxp type cifs (rw,mand)

4. umount
$ sudo umount ~/Desktop/winxp


Refer to:
Accessing an SMB Share With Linux Machines

2009/06/29

Pyrex- 连接Python与C的桥梁

没有评论:
使用Pyrex将从Pyrex代码生成一个C源文件,编译该C源文件即可生成Python的扩展模块。从而使编写Python的C扩展更加容易。Pyrex在 Python 中添加了类型声明,使得Python与C数据类型相互转换变得容易。
ubuntu 下安装: sudo apt-get install pyrex

windows 下安装: 从其官方网站http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex下载Pyrex的ZIP文件。将其解压后,进入其目录,运行如下所示命令将安装Pyrex。
python setup.py install
它将 pyrexc.py放在 c:\python25\Scripts\目录下。


首先编写如下所示“test.pyx”文件。
def test(): return 'A test file!'

windows下转换test.pyx成C, 运行如下所示的命令:
c:\python25\python.exe c:\python25\Scripts\pyrexc.py test.pyx
运行完命令后将在目录中生成“test.c”.

在VC++ 中将“test.c”编译或链接。


Pyrex文件语法

Pyrex文件完全使用了Python的语法。在编写Pyrex文件时,只需按照Python的语法编写即可。在Pyrex中可以定义C语言中的结构体、枚举等类型,也可以使用C语言中的数据类型。

1.数据类型

Pyrex定义了与C语言中相对应的数据类型,使用“cdef”可以在Pyrex中使用C语言中的数据类型。代码如下所示。
cdef char *s # 相当于C中的字符串
cdef int x,y # 相当于C中的int型
cdef int z[4] # 相当于C中的数组
cdef float f # 相当于C中的浮点型
cdef int *p # 相当于C中的指针

2.结构体、联合及枚举

除了定义C中的数据类型以外,还可以使用“cdef”定义C中的结构体、联合、枚举等。代码如下所示。
cdef struct Human: # 定义结构体
char *name
char *sex
int age
cdef union Fruit: # 定义联合体
char *apple
char *banana
char *orange
cdef enum: #定义枚举
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

3.函数

使用“cdef”可以像使用Python中的 “def”一样来定义一个函数。在Pyrex文件中既可以使用“def”来定义函数,也可以使用“cdef”来定义函数。不同的是,使用“def”定义的 函数,只能使用Python的数据类型,而使用“cdef”定义的函数则可以使用C中的数据类型。另外,使用“def”定义的函数可以被模块导出,在 Python中使用。而使用“cdef”定义的函数则不能被Python使用。代码如下所示。
cdef int sum(int x, int y): # 使用C数据类型定义函数
return x + y
cdef sum(x, y): # 如果没有声明参数类型,则表示为Python中的类型
return x + y
cdef object sum(object x, object y): # 使用object显式地表示参数为Python中的类型
return x + y

4.使用类

使用“cdef”也可以在Pyrex文件中定义类。需要注意的是如果通过继承创建类,则父类应该在该Pyrex文件中定义,否则应该使用“extern”表示父类在外部定义。代码如下所示。
cdef class Stud: # 使用cdef定义类
def setname(self,n): # 定义setname方法
self.name = n
def showname(self): # 定义showname方法
print self.name
cdef class Student(Stud): # 通过继承创建类
def setnum(self,n): # 定义setnum方法
self.num = n
def shownum(self): # 定义shownum方法
print self.num

5.使用include和外部C函数

Pyrex支持类似于C语言头文件的“.pxi”文 件。使用“.pxi”可以将较大的Pyrex文件分成多个文件,这样便于维护。“.pxi”文件像C语言中的头文件一样,只要使用“include”包含 就可以了。除此以外,在Pyrex中也可以使用C语言头文件中声明的函数原型。例如使用Python/C API中的 PyRun_SimpleString函数,则可以使用如下写法。
cdef extern from "Python.h":
int PyRun_SimpleString(char *command)

python使用pyrex编译成可执行文件

没有评论:
使用pyrex,python完全可以用来开发商业软件,而不用担心源代码泄露。
在http: //www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/下载。本来Pyrex是一个用来混合 编写python和c程序的东西,然后转换为c代码,再编译成可执行文件。于是这里就相当于提供了一种方法可以将python代码转换为c代码,这样就可 以把python程序编译为真正的可执行文件了。

而py2exe只是一个对python程序打包的工具。它可以让这个程序脱离python环境来执行,但并不能保护源代码,因为源 代码其实也包含在其中。

步骤:
1。使用obfuscator 混淆 python 代码;
2。使用 pyrex转换成C代码;
3。编译成exe或者dll库。


假设我们有一个简单的python程序,文件名为 go.py
def add(a, b):
print a+b # 为了方便看到函数调用,输出一下
retur a+b
仅仅做一个简单的加法操作。那我们想把它编译为可执行文件的话,需要进行以下几步:
1.修改go.py文件,在里面添加一个c函数,当然要用Pyrex的语法,用这个函数来调用python程序的入口函数(在这里就是add了)。修改go.py为go.pyx。
在这里就是添加一个:
cdef public int c_add(int a, int b):
return add(a, b)
2.添加一个头文件 go.pxi,让主函数能找到go.py里的c函数的申明
cdef extern int (c_add(int, int))

3.编写一个主函数文件main.c,在该主函数中包含go.h(这个文件会自动生成), 并调用前面设计的c函数。
#include
#include
#include
#include "go.h"

int main(int argc, char *argv[])
{
Py_Initialize();

initgo(); // 这个地方的函数名字为init加上模块名,就是原来那个py文件的名字
c_add(2, 5);

Py_Finalize();
return 0;
}
好了,现在编译就是:
pyrexc go.pyx
gcc go.c main.c -I/usr/include/python2.5 -L/usr/lib/ -lpython2.5 -o go
就生成了叫go的可执行文件,执行它,就得到了想要的结果!

注:此方法在linux上通过。

2009/06/20

ubuntu下比较文件

没有评论:
under terminal:
diff file1 file2
vimdiff file1 file2
gvimdiff file1 file2 (图形界面)

python的调试

没有评论:
一般直接看stderr 输出, 或者打印到stdout。如某些情况无法在terminal看到输出( 如python非主程序,被C调用 ),可以重定向到文件:

# in python script
stdout = open("file.log", "w")
stderr = stdout

print "debug thing..."

然后到文件中查看。

更进一步,如果需要单步跟踪,可以使用 pdb 调试。 其在windows下为 wxpython + winpdb

gparted: ubuntu下分区工具

没有评论:
本机在一个物理硬盘上装了两个操作系统:Ubuntu9.04 and Windows XP.分别在D:, C:。 一不小心ubuntu分区给少了,现需要重新划分其分区大小,而不影响windows系统。

________________________________________________________________________
|Windows NTFS _____________________| Ubuntu ext3_____ |Ubuntu swap|
________________________________________________________________________

使用 gparted 工具:

1. Get GParted and burn it into a CD.
2. Boot machine from this CD.
3. Delete ubuntu partition, and create new one
4. Reinstall Ubuntu system.

Note: Gparted 也可 resize, delete, and extend partitions.

2009/05/29

windows XP 下用virtual box安装 ubuntu

没有评论:
虚拟机软件 :
Virtualbox是一个十分小
巧的虚拟化 软件,开源免费,相当不错。而且基本功能都具备,个人使用完全没有问题。约20M。 2008年2月virtualbox原来的公司 innotek被sun收购。

VMware Workstation with ACE, 600多M的安装包,适合公司内使用,便于管理多个设备。

Virtual PC 为微软产品。

本文介绍如何在windows XP 下用virtual box安装 ubuntu9.04

1. 安装 virtual box, 运行
点击“new”按钮创建一个ubuntu虚拟机

2. 不着急运行虚拟机,先配置ISO虚拟光盘。点击“setting”,在“光驱”选项中勾选“分配光驱”,点虚拟光盘。打开,创建一个并指向硬盘上的文件(下载 ubuntu-9.04-desktop-i386.iso文件)。

3 运行该虚拟机。会提示安装,余下皆如直接安装ubuntu过程。在预留硬盘空间时,选择 动态调整大小,并使用整个“硬盘”。该操作不会覆盖windows host也不占用整个空间,虚拟机只是在你的windows下开辟了一个目录存放。

注意: right ctrl 为切换键, right ctrl + F 为全屏切换。

其他问题:
1. VirtualBox Ubuntu全屏 , 分辨率
2. 共享文件
解决办法:
点击vbox菜单 devices -> install guest additions (似乎无反应). 重启后会发现在Ubuntu桌面上多出一个vbox光盘图标,这张光盘默认被自动加载到了文件夹/media/cdrom0 (或 链接 /cdrom )。

进入命令行终端,输入:
cd /media/cdrom0
sudo ./VboxLinuxAdditions.run
开始安装工具包。安装完毕后会提示要重启Ubuntu。之后屏幕分辨率问题应该解决。 windows 与ubuntu之间共享可以简单处理如下: windows设置共享目录, ubuntu connects to server。 或
借助virtual box设置共享文件夹
重启完成后点击"设备(Devices)" -> 共享文件夹(Shared Folders)菜单,添加一个共享文件夹,选项Make Permanent是指该文件夹是否是持久的。共享名可以任取一个自己喜欢的,比如"flamingo",尽量使用英文名称。
挂载共享文件夹
重新进入虚拟Ubuntu,在命令行终端下输入:
sudo mkdir /mnt/shared
sudo mount -t vboxsf flamingo /mnt/shared
其中"flamingo"是之前创建的共享文件夹的名字。OK,现在Ubuntu和主机可以互传文件了。
假如您不想每一次都手动挂载,可以在/etc/fstab中添加一项
flamingo /mnt/shared vboxsf rw,gid=100,uid=1000,auto 0 0
这样就能够自动挂载了。
注意:
共享文件夹的名称千万不要和挂载点的名称相同。比如,上面的挂载点是/mnt/shared,如果共享文件夹的名字也是shared的话,在挂载的时候就会出现如下的错误信息(看http://www.virtualbox.org/ticket/2265):
/sbin/mount.vboxsf: mounting failed with the error: Protocol error
原因分析可以看《Tips on running Sun Virtualbox》的Shared Folder on a Linux Guest节。
卸载的话使用下面的命令:
sudo umount -f /mnt/shared

2009/05/12

Ubuntu 9.04: firefox中不能输入中文

没有评论:
问题: firefox上不能用 ctrl+空格 启动scim输入法

解决:
1. 找到firefox 3.0.10启动脚本位置 /usr/bin/firefox

2. 用vi或其他编辑器打开/usr/bin/firefox,在文件开头处加入如下红色内容:
MOZDIR=$HOME/.mozilla
LIBDIR=/usr/lib/firefox-3.0.3
APPVER=3.0
META_NAME=firefox
GDB=/usr/bin/gdb
DROPPED=abandoned

XMODIFIERS=@im=SCIM
GTK_IM_MODULE=scim-bridge
export XMODIFIERS GTK_IM_MODULE

2009/05/06

Python 中循环引用导致内存泄漏

没有评论:
python的垃圾收集功能。首先python中的所有对象都是继承object对象,python源码中关于object类型的定义:
[object.h]
typedef struct _object{
int ob_refcnt;
struct _typeobject * ob_type;
} PyObject;
其中ob_type是用来确定对象类型的变量,而ob_refcnt是用于垃圾收集的对象的引用计数。当对象创建的时候此成员的值就是1,例如 a=MyType(),a的引用计数就是1,如果进行对象赋值操作,例如b = a, a的引用计数就变成2。相对的,如果再运行b = c,那么a的引用计数就减1. 当对象的引用计数为0时,表明没有其他对象引用该对象。该对象所分配的内存就可以回收了

当一个对象的引用计数减少至零时,它就会在适当时机被垃圾回收车拉走。然而,特定情况(循环引用)会阻止垃圾回收车销毁不再使用的对象,看下面的例子:

1 a = { } # a 的引用为 1
2 b = { } # b 的引用为 1
3 a['b'] = b # b 的引用增 1,b的引用为2
4 b['a'] = a # a 的引用增 1,a的引用为 2
5 del a # a 的引用减 1,a的引用为 1
6 del b # b 的引用减 1, b的引用为 1

在这个例子中,del语句减少了 a 和 b 的引用计数并删除了用于引用的变量名,可是由于两个对象各包含一个对方对象的引用,虽然最后两个对象都无法通过名字访问了,但引用计数并没有减少到零。因此这个对象不会被销毁,它会一直驻留在内存中,这就造成了内存泄漏。

解决办法1: break the circle.
before 5: a['b'] = None

因此,有 __del__() 函数的对象(如list,dict)间的循环引用是导致内存泄漏的主凶。特别说明:对没有 __del__() 函数的 Python 对象(如int)间的循环引用,是可以被自动垃圾回收掉的。

慎写自己的__del__() 函数啊 :-(

解决办法2:
定期的运行 pythn gc module的搜索器,若发现一个对象已经无法被访问 (untouchable),不论该对象引用计数是否为 0 ,都主动销毁它 del gc.garbage[:]。通过 gc 模块的函数来进行调整和控制gc.enable()

print 'begin collect...'
_unreachable = gc.collect()
print 'unreachable object num:%d' % _unreachable
print 'garbage object num:%d' % len(gc.garbage)
del gc.garbage[:]

解决办法3: (调试)
# 通过引用计数判断数据单元是否可以回收
# 通过扩展模块gc中的接口可以分析调试垃圾回收的情况

使用get_objects( )方法可以取得当前所有不能回收的对象(引用计数不为0)的列表
可以写个循环把他们都打印出来调试。该方法只执行一次,因为 它本生会增加变量的引用,特别是在有内存泄露的情况下.
For example:

# after potential wrong code
objs = gc.get_objects()
for obj in objs:
if isinstance( obj, XXX): print obj # check objects here





References:
[1] Python的Garbage Collector module (import gc)
http://docs.python.org/library/gc.html

[2] http://blog.csdn.net/horin153/archive/2007/06/08/1644512.aspx

Python和C混合编程时需注意内存泄漏

没有评论:
看下面的例子:

PyObject* py_func(PyObject *self, PyObject *args)
{
PyObject *pStr = Py_BuildValue("s", "a string for test....");
PyObject *pList = PyList_New(1);
PyList_SetItem(pList, 0, pStr);
Py_DECREF(pStr); // decrease the reference of pStr.
return pList;
}

当pStr被创建时,引用计数增1,加入pList后,引用计数又增1;同样,pList被创建时,引用计数也增1;pList返回给Python 使用,当不再需要时,pList和其包含的每个元素的引用计数都将减1;如果我们不在pStr加入pList后对其引用计数减1,每个创建的pStr都不会被销毁,一直保存在内存中。

另: 以下方式只对 PyList_SetItem(), PyTuple_SetItem()有效,其他的则会产生内存泄露

PyFunctions_XXXX(pList, 0, Py_BuildValue("s", "never destroy..."));

python文档告诉我们这两个函数是 burrow reference.

2009/05/05

C扩展接口程序中的Python引用计数器泄漏

没有评论:
如果是python code产生的内存泄露,可以用gc module来调试;

如果是接口C程序产生的内存泄露,可以用工具linux ,valgrind 或 vc++ 并 visual leak detector来调试。个人感觉后者更简单易用。

valgrind 为linux 下free 内存调试软件

http://valgrind.org/

内存泄漏调试过程
* 使用分析工具Valgrind对整个应用程序的运行过程进行分析
* 运行命令行
valgrind -v --leak-check=yes --num-callers=256 --logfile=d python d.py

分析内存占用情况
* 为valgrind增加命令行参数--show-reachable=yes,这将会把还在使用的内存情况也打印出来
* 运行命令行
valgrind -v --show-reachable=yes --leak-check=yes --num-callers=256 \
--logfile=d python d.py


附: 引用计数相关函数
(1)void Py_INCREF(PyObject *o)
void Py_XINCREF(PyObject *o)
增加引用计数,如果不确定对象o是否为空,使用后者

(2)void Py_DECREF(PyObject *o)
void Py_XDECREF(PyObject *o)
减少引用计数,如果不确定对象o是否为空,使用后者

(3)void Py_CLEAR(PyObject *o)同上

2.4以后版本使用Py_IncRef(PyObject *o), Py_DecRef(PyObject *o), Py_CLEAR(PyObject *o)

检查C++中的内存泄漏 -Visual Leak Detector

没有评论:

Visual Leak Detector(VLD)是一款用于Visual C++的免费的内存泄露检测工具,用户可从http://www.codeproject.com/tools/visualleakdetector.asp下载,该软件以库形式与用户的被测工程一起使用,由于VLD是按LGPL(GNU LESSER GENERAL PUBLIC LICENSE)协议对外开源,所以不必担心版权问题。

使用VLD

先从网站下载VLDzip包,当前最高版本是V1.0,解压后得到vld.hvldapi.hvld.libvldmt.libvldmtdll.libdbghelp.dll等文件,把这些所有.h头文件拷贝到VC默认的include目录下,将所有.lib文件拷贝到VC默认的lib目录下,安装工作就完成了。
使用VLD很简单,只须在包含入口函数的CPPC文件中把vld.h头文件包含进来即可。该include语句要求放在最前面,如果当前工程定义预编译head文件(如stdafx.h),则放在“#include ”语句之后就可以了。之后正常编译、按Debug方式运行被测程序,等程序运行结束时,查阅VCoutput窗口,会有“Visual Leak Detector is now exiting.”一句打印信息,在这条件信息之前,如果当前程序没有内存泄露会有“No memory leaks detected.”信息打印,但如果有内存泄露,将有类似如下信息打印:
C:"VcTester21"sample"vc6"SampleMain.c (80): main
crt0.c (206): mainCRTStartup
0x7C816FD7 (File and line number not available): RegisterWaitForInputIdle
Data: CD CD CD CD CD ........ ........
Visual Leak Detector detected 1 memory leak.
这个信息指明当前发生内存泄露所在的函数及源文件行号,泄露内存块的地址、长度及当前内存值。用鼠标双击指示源码行的提示信息,VC即自动跳转到相应代码行,我们就很方便的知道是哪一行出错了。
可以看出,VLD用起来很简单,对它的实现原理感兴趣的朋友可以阅读VLD源码
memoryleak.cpp
#include "stdafx.h"
#include

int _tmain(int argc, _TCHAR* argv[])
{
char *pTest = new char[10];

return 0;
}


从output窗口我们可以看到有内存泄漏:
Visual Leak Detector Version 1.0 installed (multithreaded DLL).
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 109 at 0x003ACEC8: 10 bytes ----------
Call Stack:
e:\example\memoryleak\memoryleak\memoryleak.cpp (10): wmain
f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (583): __tmainCRTStartup
f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (403): wmainCRTStartup
0x7C816FD7 (File and line number not available): RegisterWaitForInputIdle
Data:
CD CD CD CD CD CD CD CD CD CD ........ ........

Visual Leak Detector detected 1 memory leak.
“MemoryLeak.exe”: 已卸载“C:\WINDOWS\system32\dbghelp.dll”
“MemoryLeak.exe”: 已卸载“C:\WINDOWS\system32\version.dll”
Visual Leak Detector is now exiting.
程序“[5056] MemoryLeak.exe: 本机”已退出,返回值为 0 (0x0)。
很方便我们找出内存泄漏的地方!

2009/05/01

Install CGAL-python under Ubuntu 9.04

没有评论:
如何安装:

问题在于ubuntu 9.04 uses python 2.6 instead of python 2.5, which makes the previous build of cgal-python0.9.3 invalid. Need to rebuild cgal-python.

Since the newest CGAL version is 3.4, we upgrade it from 3.3.

--------------------------
install boost-python

still use libboost-python1.34.1. note that 1.37.0 does not make the cgal-python building correct. If 1.37.0 exists, remove from synatic.

sudo apt-get install libboost-python1.34.1
sudo apt-get install libboost-python-dev

-------------------------
install CGAL 3.4

1. download
http://gforge.inria.fr/frs/?group_id=52

2. sudo apt-get install cmake

3. follow the instruction of INSTALL under CGAL-3.4 directory
cmake .

4. make

5. sudo make install

------------------------

install cgal-python0.9.4 beta1 (the latest. I guess 0.9.3 is also OK.)


download the package, and do
export CPATH=/usr/include/python2.6:$CPATH
export LIBRARY_PATH=/usr/local/lib:$LIBRARY_PATH

python setup.py build
python setup.py install (possibly as root)

2009/03/31

how to get python25_d.lib and python25_d.dll

没有评论:
If do want to use "python25_d.lib" and/or "python25_d.dll" to debug python scripts,
can use Visual C++ to compile python25 source code.

1. download python-2.5.4.tgz (11M) from python's official website:
http://www.python.org/ftp/python/2.5.4/Python-2.5.4.tgz

2. Unzipped and look for directory "python-2.5.4\PCbuild8\"
(Note that: directory ".\PCbuild\" is for VC 7.0)

Use VC++ 2005 (ver8.0) to open the pcbuild.sln under directory ".\PCbuild8\". You will see 20 projects. Build only two projects "python" and "pythoncore".


3. There will be two files "python25_d.lib" and "python25_d.dll" generated under directory ".\PCbuild8\win32debug". Copy them into "c:\python25\libs" and "c:\windows\system32"
respectively. Previously, "python25.dll" and "python25.lib" already there.


4. Turn on "debug" in VC and rebuild. Succeed.

However, I did not figure out how to use debug version in VC to debug into my python file.:-(

Note: Python's latest version is 2.6. But since I use "pylab/matplotlib" which currently only offers package ver0.98 for python2.5 under windows. So,... python2.5.4 is my choice.

2009/03/29

C++和python的相互调用-II

没有评论:
编写扩展 Use python to write extension for C++ program

Visual C++ 2005 下创建新 Win32/ Win32 DLL project. 这样不用手写 *.def文件和手工编译链接。
然后将附带cpp文件做成 dll.

Python can only use this "*.dll" by changing it to "*.pyd".

Example:
1. Change the built "pyUtil.dll" to file name "pyUtil.pyd".
2. In python command line:
import sys
sys.path.append(".\\") # where pyUtil.pyd locates
# Or, put pyUtil.pyd file under python dll directory, "C:\Python25\DLLs".
# Note: "C:\Python25\libs" store static library like "pyUtil.lib".
import pyUtil
pyUtil.Recognise("ddddd")


C program can use python extension like static library.
That is: C program with pyUtil.py under the same directory,
which needs support of "C:\python25\libs\python25.lib".

C program can use this "*.dll" normally.
The usage is same as above.
Note that put pyUtil.dll under directory "c:\windows\system32\".



Source code for dll:
//////////////////////////////////////////////////////////////////
// pyUtil.cpp :


#ifdef _MANAGED
#pragma managed(push, off)
#endif


#include "stdafx.h"
#include "string.h"
#include "Python.h" // added

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
/*
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
*/
return TRUE;
}


/////////// my code
std::string Recognise_Img(const std::string url)
{ return "hello, " +url;
}

static PyObject* Recognise(PyObject *self, PyObject *args)
{
const char *url;
std::string sts;

if (!PyArg_ParseTuple(args, "s", &url)) // parse python objects from input
return NULL;

sts = Recognise_Img(url); // add your code here.

return Py_BuildValue("s", sts.c_str() ); // return python objects if used in python
}


static PyMethodDef AllMyMethods[] = { // declare of function list
{"Recognise", Recognise, METH_VARARGS}, // function name
{NULL, NULL} // need this to end decl
};

extern "C" PyMODINIT_FUNC initpyUtil() // initMyPythonModuleName
{
PyObject *m, *d;
m = Py_InitModule("pyUtil", AllMyMethods); // Module Name = file name
d = PyModule_GetDict(m);
}



#ifdef _MANAGED
#pragma managed(pop)
#endif

2009/03/23

C++扩展和嵌入Python

没有评论:

C++扩展和嵌入Python
作者:胡金山 来源:www.vckbase.com

Paper source

下载源代码

Python简介

Python是一种简单易学,功能强大的解释型编程语言,它有简洁明了的语法,高效率的高层数据结构,能够简单而有效地实现面向对象编程,特别适用于快速应用程序开发,也可以用来开发大规模的重要的商业应用。Python是一个理想的脚本语言。
Python免费开源,可移植到多种操作系统,只要避免使用依赖于特定操作系统的特性,Python程序无需修改就可以在各种平台上面运行。
Python拥有现代编程语言所具有的一切强大功能,Python标准库十分庞大,可以帮助开发者处理各种工作,如:图形用户界面、文件处理、多媒体、正 则表达式、文档生成、单元测试、线程、数据库、网络通讯、网页浏览器、CGI、FTP、电子邮件、XML、HTML、WAV文件、密码系统、Tk和其他与 系统有关的操作。只要安装了Python,这些功能都是可用的除了标准库以外,还有许多其他高质量的库,如wxPython、Twisted和 Python图形库等等数不胜数。
Python容易扩展和嵌入。Python提供的许多标准模块支持C或者C++接口。Python和C可以一起工作,它可以嵌入到C或者C++的应用程序 当中,因此可用Python语言为应用程序提供脚本接口,由于支持跨语言开发,可用Python设计概念化应用程序,并逐步移植到C,使用前不必用C 重写应用程序。(Jython使Python可以和Java一起工作,使开发者可以在Python里面调Java的包,也可以在Java里面使用 Python的对象。还有更妙的,由于Jython的解释器完全用Java编写,因此可以在支持Java的任何平台上部署Python程序,甚至WEB浏 览器也可以直接运行Python脚本。)

提出问题

在某个C++应用程序中,我们用一组插件来实现一些具有统一接口的功能,我们使用Python来代替动态链接库形式的插件,这样可以方便地根据需求的变化 改写脚本代码,而不是必须重新编译链接二进制的动态链接库。Python强大的功能足以胜任,但是有一些操作系统特定的功能需要用C++来实现,再由 Python调用。所以,最基础地,我们需要做到:
  1. 把Python嵌入到C++应用程序中,在C++程序中调用Python函数和获得变量的值;
  2. 用C++为Python编写扩展模块(动态链接库),在Python程序中调用C++开发的扩展功能函数。

常用的Python/C API介绍

下面是例子中用到的几个Python/C API的简要介绍及示例代码。注意,这并不是这些函数的详细介绍,而仅仅是我们所用到的功能简介,更详细内容请参考文档[1]、[2]、[3]、[4]。
打开Microsoft Visual Studio .NET 2003,新建一个控制台程序
  1. #include

并在main函数里加入示例代码。
  1. //先定义一些变量
  2. char *cstr;
  3. PyObject *pstr, *pmod, *pdict;
  4. PyObject *pfunc, *pargs;

1. void Py_Initialize( )

初始化Python解释器,在C++程序中使用其它Python/C API之前,必须调用此函数,如果调用失败,将产生一个致命的错误。例:
  1. Py_Initialize();

2. int PyRun_SimpleString( const char *command)

执行一段Python代码,就好象是在__main__ 函数里面执行一样。例:
  1. PyRun_SimpleString("from time import time,ctime "
  2. "print ''Today is'',ctime(time()) ");

3. PyObject* PyImport_ImportModule( char *name)

导入一个Python模块,参数name可以是*.py文件的文件名。相当于Python内建函数__import__()。例:
  1. pmod = PyImport_ImportModule("mymod"); //mymod.py

4. PyObject* PyModule_GetDict( PyObject *module)

相当于Python模块对象的__dict__ 属性,得到模块名称空间下的字典对象。例:
  1. pdict = PyModule_GetDict(pmod);

5. PyObject* PyRun_String( const char *str, int start, PyObject *globals, PyObject *locals)

执行一段Python代码。
  1. pstr = PyRun_String("message", Py_eval_input, pdict, pdict);

6. int PyArg_Parse( PyObject *args, char *format, ...)

解构Python数据为C的类型,这样C程序中才可以使用Python里的数据。例:
  1. /* convert to C and print it*/
  2. PyArg_Parse(pstr, "s", &cstr);
  3. printf("%s ", cstr);

7. PyObject* PyObject_GetAttrString( PyObject *o, char *attr_name)

返回模块对象o中的attr_name 属性或函数,相当于Python中表达式语句:o.attr_name。例:
  1. /* to call mymod.transform(mymod.message) */
  2. pfunc = PyObject_GetAttrString(pmod, "transform");

8. PyObject* Py_BuildValue( char *format, ...)

构建一个参数列表,把C类型转换为Python对象,使Python可以使用C类型数据,例:
  1. cstr="this is hjs''s test, to uppercase";
  2. pargs = Py_BuildValue("(s)", cstr);

9. PyEval_CallObject(PyObject* pfunc, PyObject* pargs)

此函数有两个参数,都指向Python对象指针,pfunc是要调用的Python 函数,通常可用PyObject_GetAttrString()获得;pargs是函数的参数列表,通常可用Py_BuildValue()构建。例:
  1. pstr = PyEval_CallObject(pfunc, pargs);
  2. PyArg_Parse(pstr, "s", &cstr);
  3. printf("%s ", cstr);

10. void Py_Finalize( )

关闭Python解释器,释放解释器所占用的资源。例:
  1. Py_Finalize();


Python2.4环境没有提供调试版本的Python24d.lib,所以上述示例在release模式下编译。编译完成后,把可行文件和附2给出的 mymod.py文件放在一起,再点击即可运行。为了简化编程,附3 给出了simplepy.h。这样,调用mymod.transform变成如下形式:
  1. //#include”simplepy.h”
  2. CSimplepy py;
  3. py.ImportModule("mymod");
  4. std::string str=py.CallObject("transform",
  5. "this is hjs''s test, to uppercase");
  6. printf("%s ", str.c_str());


接下来,我们来用C++为Python编写扩展模块(动态链接库),并在Python程序中调用C++开发的扩展功能函数。生成一个取名为pyUtil的Win32 DLL工程,除了pyUtil.cpp文件以外,从工程中移除所有其它文件,并填入如下的代码:
  1. // pyUtil.cpp
  2. #ifdef PYUTIL_EXPORTS
  3. #define PYUTIL_API __declspec(dllexport)
  4. #else
  5. #define PYUTIL_API __declspec(dllimport)
  6. #endif
  7. #include
  8. #include
  9. #include
  10. BOOL APIENTRY DllMain( HANDLE hModule,
  11. DWORD ul_reason_for_call,
  12. LPVOID lpReserved
  13. ?)
  14. {
  15. switch (ul_reason_for_call)
  16. {
  17. case DLL_PROCESS_ATTACH:
  18. case DLL_THREAD_ATTACH:
  19. case DLL_THREAD_DETACH:
  20. case DLL_PROCESS_DETACH:
  21. break;
  22. }
  23. return TRUE;
  24. }
  25. std::string Recognise_Img(const std::string url)
  26. {
  27. //返回结果
  28. return "从dll中返回的数据... : " +url;
  29. }
  30. static PyObject* Recognise(PyObject *self, PyObject *args)
  31. {
  32. const char *url;
  33. std::string sts;
  34. if (!PyArg_ParseTuple(args, "s", &url))
  35. return NULL;
  36. sts = Recognise_Img(url);
  37. return Py_BuildValue("s", sts.c_str() );
  38. }
  39. static PyMethodDef AllMyMethods[] = {
  40. {"Recognise", Recognise, METH_VARARGS},//暴露给Python的函数
  41. {NULL, NULL} /* Sentinel */
  42. };
  43. extern "C" PYUTIL_API void initpyUtil()
  44. {
  45. PyObject *m, *d;
  46. m = Py_InitModule("pyUtil", AllMyMethods); //初始化本模块,并暴露函数
  47. d = PyModule_GetDict(m);
  48. }


在Python代码中调用这个动态链接库:
  1. import pyUtil
  2. result = pyUtil.Recognise("input url of specific data")
  3. print "the result is: "+ result

用C++为Python写扩展时,如果您愿意使用Boost.Python库的话,开发过程会变得更开心J,要编写一个与上述pyUtil同样功能的动态 链接库,只需把文件内容替换为下面的代码。当然,编译需要boost_python.lib支持,运行需要boost_python.dll支持。
  1. #include
  2. #include
  3. using namespace boost::python;
  4. #pragma comment(lib, "boost_python.lib")
  5. std::string strtmp;
  6. char const* Recognise(const char* url)
  7. {
  8. strtmp ="从dll中返回的数据... : ";
  9. strtmp+=url;
  10. return strtmp.c_str();
  11. }
  12. BOOST_PYTHON_MODULE(pyUtil)
  13. {
  14. def("Recognise", Recognise);
  15. }


所有示例都在Microsoft Windows XP Professional + Microsoft Visual Studio .NET 2003 + Python2.4环境下测试通过,本文所用的Boost库为1.33版本。

参考资料

  1. Python Documentation Release 2.4.1. 2005.3.30,如果您以默认方式安装了Python2.4,那么该文档的位置在C:\Program Files\Python24\Doc\Python24.chm;
  2. Michael Dawson. Python Programming for the Absolute Beginner. Premier Press. 2003;
  3. Mark Lutz. Programming Python, 2nd Edition. O''Reilly. 2001.3 ;
  4. Mark Hammond, Andy Robinson. Python Programming on Win32. O''Reilly. 2000.1 ;
Python主页:http://www.python.org
Boost库主面:www.boost.org

附1 text.txt

this is test text in text.txt.

附2 mymod.py

  1. import string
  2. message = ''original string''
  3. message =message+message
  4. msg_error=""
  5. try:
  6. text_file = open("text.txt", "r")
  7. whole_thing = text_file.read()
  8. print whole_thing
  9. text_file.close()
  10. except IOError, (errno, strerror):
  11. print "I/O error(%s): %s" % (errno, strerror)
  12. def transform(input):
  13. #input = string.replace(input, ''life'', ''Python'')
  14. return string.upper(input)
  15. def change_msg(nul):
  16. global message #如果没有此行,message是函数里头的局部变量
  17. message=''string changed''
  18. return message
  19. def r_file(nul):
  20. return whole_thing
  21. def get_msg(nul):
  22. return message

附3 simplepy.h

  1. #ifndef _SIMPLEPY_H_
  2. #define _SIMPLEPY_H_
  3. // simplepy.h v1.0
  4. // Purpose: facilities for Embedded Python.
  5. // by hujinshan @2005年9月2日9:13:02
  6. #include
  7. using std::string;
  8. #include
  9. //--------------------------------------------------------------------
  10. // Purpose: ease the job to embed Python into C++ applications
  11. // by hujinshan @2005年9月2日9:13:18
  12. //--------------------------------------------------------------------
  13. class CSimplepy // : private noncopyable
  14. {
  15. public:
  16. ///constructor
  17. CSimplepy()
  18. {
  19. Py_Initialize();
  20. pstr=NULL, pmod=NULL, pdict=NULL;
  21. pfunc=NULL, pargs=NULL;
  22. }
  23. ///destructor
  24. virtual ~CSimplepy()
  25. {
  26. Py_Finalize();
  27. }
  28. ///import the user module
  29. bool ImportModule(const char* mod_name)
  30. {
  31. try{
  32. pmod = PyImport_ImportModule(const_cast(mod_name));
  33. if(pmod==NULL)
  34. return false;
  35. pdict = PyModule_GetDict(pmod);
  36. }
  37. catch(...)
  38. {
  39. return false;
  40. }
  41. if(pmod!=NULL && pdict!=NULL)
  42. return true;
  43. else
  44. return false;
  45. }
  46. ///Executes the Python source code from command in the __main__ module.
  47. ///If __main__ does not already exist, it is created.
  48. ///Returns 0 on success or -1 if an exception was raised.
  49. ///If there was an error, there is no way to get the exception information.
  50. int Run_SimpleString(const char* str)
  51. {
  52. return PyRun_SimpleString(const_cast(str) );
  53. }
  54. ///PyRun_String("message", Py_eval_input, pdict, pdict);
  55. ///Execute Python source code from str in the context specified by the dictionaries globals.
  56. ///The parameter start specifies the start token that should be used to parse the source code.
  57. ///Returns the result of executing the code as a Python object, or NULL if an exception was raised.
  58. string Run_String(const char* str)
  59. {
  60. char *cstr;
  61. pstr = PyRun_String(str, Py_eval_input, pdict, pdict);
  62. if(pstr==NULL)
  63. throw ("when Run_String, there is an exception was raised by Python environment.");
  64. PyArg_Parse(pstr, "s", &cstr);
  65. return string(cstr);
  66. }
  67. ///support olny one parameter for python function, I think it''s just enough.
  68. string CallObject(const char* func_name, const char* parameter)
  69. {
  70. pfunc=NULL;
  71. pfunc = PyObject_GetAttrString(pmod, const_cast(func_name));
  72. if(pfunc==NULL)
  73. throw (string("do not found in Python module for: ")
  74. +func_name).c_str();
  75. char* cstr;
  76. pargs = Py_BuildValue("(s)", const_cast(parameter));
  77. pstr = PyEval_CallObject(pfunc, pargs);
  78. if(pstr==NULL)
  79. throw ("when PyEval_CallObject, there is an exception was raised by Python environment");
  80. PyArg_Parse(pstr, "s", &cstr);
  81. return string(cstr);
  82. }
  83. //PyObject *args;
  84. //args = Py_BuildValue("(si)", label, count); /* make arg-list */
  85. //pres = PyEval_CallObject(Handler, args);
  86. protected:
  87. PyObject *pstr, *pmod, *pdict;
  88. PyObject *pfunc, *pargs;
  89. };
  90. #endif // _SIMPLEPY_H_
  91. // end of file

2009/03/20

C++和Python的相互调用

没有评论:
c++和python的互相调用


简单配置如下:

python安装目录: C:\Python26
头文件包含:
VStudio->Tools->Options->Directories->Include files 加入 C:\PYTHON26\INCLUDE
库文件包含:
VStudio->Tools->options->Directories->Library files 加入 C:\PYTHON26\LIBS

如果是debug版本,有可能会提示can't open file "python26_d.lib"没有调试版本的类库.
Solution: 把C:\Python26\libs\python26.lib复制一个python26_d.lib即可
否则直接用release版本就行; Or change python26_d.lib to python26.lib in "pyconfig.h" file, and comment "#define Py_DEBUG".


工程文件中包含了c++调用python中的函数,也同时把c++的函数做成了dll,以供python之调用;
所以也就发生另个一个问题,c++调用python时,最后关闭了python解释器
Py_Finalize(); 以至于python又调用dll时,发生错误;所以在生成dll时,注释掉
Py_Initialize();以及Py_Finalize();


若没有装VC,可以去微软网站下一个C++的编译器 VCTookitSetup.exe.
Under VC->VStudio Tools-> VStudio 2005 command prompt , 执行命令 cl cfile编译。


举例:

1、C中调用PYTHON
  #include
  int main(int argc, char *argv[])
  {
  Py_Initialize();
  PyRun_SimpleString("from time import time,ctime\n"
  "print 'Today is',ctime(time())\n");
  Py_Finalize();
  return 0;
  }
  直接用CL 文件名 编译就是

2、
PYTHON调用由C生成的DLL
  C代码:如FOO.C
  #include
  /* Define the method table. */
  static PyObject *foo_bar(PyObject *self, PyObject *args);
  static PyMethodDef FooMethods[] = {
  {"bar", foo_bar, METH_VARARGS},
  {NULL, NULL}
  };
  /* Here's the initialization function. We don't need to do anything
  for our own needs, but Python needs that method table. */
  void initfoo()
  {
  (void) Py_InitModule("foo", FooMethods);
  }
  /* Finally, let's do something ... involved ... as an example function. */
  static PyObject *foo_bar(PyObject *self, PyObject *args)
  {
  char *string;
  int len;
  if (!PyArg_ParseTuple(args, "s", &string))
  return NULL;
  len = strlen(string);
  return Py_BuildValue("i", len);
  }
  C定义文件:foo.def
  EXPORTS
  initfoo
  编译生成foo.dll
  cl -c foo.c;
  link foo.obj /dll /def:foo.def /OUT:foo.dll
将foo.dll 改名为 foo.pyd
  在PYTHON中调用:
  import foo
  dir(foo)
  …
  即可以看到结果:
  >>> import foo
  >>> dir(foo)
  ['__doc__', '__file__', '__name__', 'bar']
  >>> ^Z
为简化python使用C的数据类型,可以 import ctypes . it is better over pyrex .


3 C调用由python生成的dll
写一个C程序,该程序存放调用python的函数接口。然后将该C程序和python程序一起做成DLL即可。


主要参考

C++ 扩展和嵌入 Python
http://www.vckbase.com/document/viewdoc/?id=1540

Anjuta: C++ IDE for Ubuntu

没有评论:
Linux下C/C++工具推荐Anjuta

vi/vim, gedit 和emacs is simple

KDeveloper is based on KDE

Eclipse, 基于Java的IDE, 慢,耗内存

NetBeans , 基于Java

基于GTK/Glade的Anjuta集成开发环境(IDE)不错,体积小,速度快,有自动代码补全和提示功能. I feel even for python IDE, anjuta can beat eric-python!

1. Install anjuta directly by menu->Applications->add/remove->programming

2. 安装C/C++开发文档
在编程的过程中有时会记不得某个函数的用法,通常这时查man手册是比较快的,所以把这个manpages-dev软件包安装上。想要看某个函数的用法就man它。
执行安装命令: sudo apt-get install manpages-dev

manpage的索引由mandb命令管理,有时在安装了新的manpage文件后,可能需要更新一下索引才能看到man -k 和man -f这些函数。
执行命令:mandb -c

然后,就可以查看这些文档了。比如,fopen的:
man fopen

3. 写个Hello World 的C++程序
在Anjuta中新建Project。出现“应用程序向导”,点“前进”;工程类型选“C++”中的“Generic C++”,之后点“前进”;“前进”;工程选项(Project Options)中,全选“否”,再点“前进”,应用即可。点左侧“工程”按钮,点工程名“foobar-cpp”,双击“main.cc”打开它,可以看到,main() 函数已预先写好了。按下“Shift+F11”编译,再按“F3”运行(这两个快捷键对应菜单在“Build”菜单下。),Anjuta的更多功能等待发掘,点击“设置”》“Plugins”...

References:
[1] http://anjuta.org/apt
[2] http://forum.ubuntu.org.cn/viewtopic.php?t=79137

2009/03/08

ctypes, pyrex and Boost

没有评论:
ctypes 是为方便python程序调用C dll程序的接口而规范数据类型。
-ctypes是一个Python模块,
-可在Python中创建和操作C语言的数据类型
-可在动态链接库中传递参数到C的函数中去

Pyrex 是将Python脚本转化为可编译的C代码,以便高效执行和被C程序调用。
- 它有多出的语法(除与python兼容外)
- 它需要 pyrexc test.pyx 生成 C代码 test.c
- 然后编译成 test.so 或 test.dll

Boost_python是方便写python程序调用C dll.


相对来说 ctypes使用较方便! 使用pyrex,如果需要在Python代码访问C代码的Struct和Union,比较麻烦。

cytpes tutorial

Pyrex - a Language for Writing Python Extension Modules

pyrex一例
1,先生成简单的
//test.h
int tadd(int a, int b);

//test.c
#include "test.h"
int tadd(int a, int b) { return a+b; };

gcc -c test.c #生成test.o
ar -rsv libtest.a test.o #生成了 libtest.a 静态库

2 测试lib是否可用
// ttest.c
#include
#include "test.h"
void main(int argc, void * argv[])
{ int c=1; c = tadd(1, 4); printf("c = %d \r\n", c); }

gcc ttest.c -ltest -L. #生成了a.out
./a.out #结果是: c = 5

证明我们的lib库是可以正常工作的


3,写一个python的模块td.pyx,调用它libtest里的tadd()函数
#td.pyx
cdef extern from "test.h":
int tadd(int i, int j)

def tdadd(int i, int j):
cdef int c
c=tadd(i, j) #在这行调用c=tadd(i, j)
return c

编译:
pyrexc td.pyx #生成 td.c
gcc -c -fPIC -I/usr/include/python2.4/ td.c #生成td.o
gcc -shared td.o -ltest -L. -o td.so #生成了td.so。这个就是python可以用的模块so

安装 pyrex,略。
测试:
import td
dir(td)
['__builtins__', '__doc__', '__file__', '__name__', 'tdadd']
td.tdadd(1,2)
3

OK。

2009/02/13

Ubuntu 8.10下如何升级eric4-python到4.3.0

没有评论:
Ubuntu下的python IDE 软件:
gedit虽然已经很好了,可还是想要一个集成开发环境。ubuntu下的
Eric python IDE 似乎还行。
Stani's Python Editor: another choice 还行,但不能 create project.
PyPE : not good
vim 但没有集成环境
sudo apt-get install vim-full vim-python
最终选用 Eric Python Editor
升级ubuntu from 8.04 to 8.10后,发现eric-python 不再能 auto python code completion (出现提示窗口,但不能选择!)。

解决方案: 重新安装eric4-4.3.0

0. uninstall previous eric4.1.0 from synaptic

1. download eric4 package from http://eric-ide.python-projects.org/eric4-download.html

2. sudo apt-get install python-qt4-dev python-qscintilla2

3. cd to eric-package directory
sudo python install.py
若提示:
Please enter the name of the Qt data directory.
(That is the one containing the 'qsci' subdirectory.)
>>
输入 /usr/share/qt4

4. 运行.
目前ubuntu source 未包含最新eric版本,因此在terminal 执行eric4 (位于/usr/local/bin/eric4)

Note: 目前eric4.3在laptop上窗口显示有问题。

2009/02/06

安装Ubuntu 8.10 带来的问题

没有评论:
Ubuntu 8.10: firefox中flash无声音
解决: sudo apt-get install flashplugin-nonfree-extrasound

启动我的python程序,多了如下两个bugs. :-(

/usr/lib/python2.5/site-packages/pytz/__init__.py:29: UserWarning: Module _mysql was already imported from /var/lib/python-support/python2.5/_mysql.so, but /var/lib/python-support/python2.5 is being added to sys.path
from pkg_resources import resource_stream

import MySQLdb
import matplotlib
会出现 UserWarning, 但顺序
import matplotlib
import MySQLdb
则不会

解释: matplotlib may import mySQLdb and a warning message is issued if mySQLdb already is imported.
而 /usr/lib/python2.5/site-packages/pytz has to do with timezones. python-tz ( pytz: python time zone)

解决方法:
1。 简易。 调整 import 顺序.
2. or look into
/usr/lib/python2.5/site-packages/pytz/__init__.py:29
找到 pkg_resources.py, 修改该文件。
/usr/lib/python2.5/site-packages/pkg_resources.py, Line 2272:

From:
if fn and normalize_path(fn).startswith(loc):
To:
if fn and (fn.startswith(loc) or normalize_path(fn).startswith(loc)):

the warning goes away.




/usr/lib/python2.5/site-packages/pytz/__init__.py:29: UserWarning: Module dateutil was already imported from /var/lib/python-support/python2.5/dateutil/__init__.py, but /var/lib/python-support/python2.5 is being added to sys.path
from pkg_resources import resource_stream

这个好像与 旧的pyc文件没有 update有关,It may be caused by outdated *.pyc files. Can try (sudo python -c 'import dateutil') - that should regenerate
outdated *.pyc files. 第二个warning消失.


/usr/lib/python2.5/site-packages/CGAL/__init__.py:3: RuntimeWarning: Python C API version mismatch for module Kernel: This Python has API version 1013, module Kernel has version 1012.
from Kernel import *
/usr/lib/python2.5/site-packages/CGAL/__init__.py:4: RuntimeWarning: Python C API version mismatch for module Triangulations_2: This Python has API version 1013, module Triangulations_2 has version 1012.
from Triangulations_2 import *
/usr/lib/python2.5/site-packages/CGAL/__init__.py:5: RuntimeWarning: Python C API version mismatch for module Triangulations_3: This Python has API version 1013, module Triangulations_3 has version 1012.
from Triangulations_3 import *

这个与 CGAL 版本落后有关, 按 cgal-python version = 0.9.3 ,python=2.5 重新自己编译. OK. (参见 cgal-python安装)


当然 Ubuntu 8.10也带来一个pylab/matplotlib的好处: pylab绘图完成后会将控制权返回,因此可以在一个canvas上interactive plotting. 以前必须关闭canvas返回。