Sunday, December 28, 2008

我知道的几个GAE blog的源码地址






我知道的几个GAE blog的源码地址
2008年07月17日 星期四 19:00
代码在 http://code.google.com/p/pyweblog/    具体样子参见:http://plog.appspot.com/

代码在 http://code.google.com/p/n23/   具体样子参见:http://n23.appspot.com/blog

代码在 http://code.google.com/p/xian-min/   具体样子参见:http://xian-min.appspot.com/

http://code.google.com/p/tublog/

http://github.com/araddon/potlatchblog/tree/master

http://code.google.com/p/gaeblog/


    代码可以自行使用SVN下载,倒腾几分钟就可以用了。哪个都行,主要是参考学习一下GAE的用法。

    前些时候看了一些源码,后来记住的中国人写的blog源码地址就这几个了。期中,pyweblog是第一个写的,N23同学在上面改了一下衍生了他自己的版本。xian-min的版本出来的比较晚。


Sunday, December 21, 2008

Python&OpenCV






Python&OpenCV





Wikipedia,自由的百科全书




目前OpenCV支持的Python版本为2.4版.所以我们这里使用2.4为范例.
但是如果你用2.5也能做到请帮忙修改一下这个页面,让大家知道2.5也可以,并且说明需要怎么设置和使用,存在什么问题.


目录

[隐藏]





安装Python


Python
一种面向对象、解释性的计算机程序设计语言,也是一种功能强大而完善的通用型语言,已经具有十多年的发展历史,成熟且稳定。这种语言具有非常简捷而清晰的
语法特点,适合完成各种高层任务,几乎可以在所有的操作系统中运行。目前,基于这种语言的相关技术正在飞速的发展,用户数量急剧扩大,相关的资源非常多。


Windows用户


Python的安装,可以直接去 http://www.python.org 下载最新版本2.5.1。

opencv4python2.5下载地址:http://www.interactive-china.net/viewthread.php?tid=235&extra=page%3D1

安装完毕之后,请把opencv4python2.5压缩包解压,然后放到你的Python安装目录的所在地。假如Python安装在
D:\Program Files\Python\,那么将解压后的文件放到 D:\Program
Files\Python\Lib\site-packages\,然后在D:\Program
Files\Python\Lib\site-packages\
里新建一个文档,保存为Opencv.pth,里面的内容写入OpenCV。这样就完成了基本的设置,可以开始在python下调用OpenCV来写东西
了。


Linux用户


Linux用户就好办了,系统默认就有,只是可能版本是2.5的.
用python --version看一下


OpenCV Python的范例


  1.  
  2. #! /usr/bin/env python
  3.  
  4. import sys
  5.  
  6. # import the necessary things for OpenCV
  7. #原先范例的格式是下面的两行,也就是from opencv.cv import*
  8. #这里需要改为import cv 和import highgui,然后就可以了。
  9. #from opencv.cv import *
  10. #from opencv.highgui import *
  11. import cv
  12. import highgui
  13.  
  14. # the codec existing in cvcapp.cpp,
  15. # need to have a better way to specify them in the future
  16. # WARNING: I have see only MPEG1VIDEO working on my computer
  17.  
  18. import ctypes
  19. H263 = 0x33363255
  20. H263I = 0x33363249
  21. MSMPEG4V3 = 0x33564944
  22. MPEG4 = 0x58564944
  23. MSMPEG4V2 = 0x3234504D
  24. MJPEG = 0x47504A4D
  25. MPEG1VIDEO = 0x314D4950
  26. AC3 = 0x2000
  27. MP2 = 0x50
  28. FLV1 = 0x31564C46
  29.  
  30. # so, here is the main part of the program
  31.  
  32. if __name__ == '__main__':
  33.  
  34. # a small welcome
  35. print "OpenCV Python capture video"
  36.  
  37. # first, create the necessary window
  38. highgui.cvNamedWindow ('Camera', highgui.CV_WINDOW_AUTOSIZE)
  39.  
  40. # move the new window to a better place
  41. highgui.cvMoveWindow ('Camera', 10, 10)
  42.  
  43. try:
  44. # try to get the device number from the command line
  45. device = int (sys.argv [1])
  46.  
  47. # got it ! so remove it from the arguments
  48. del sys.argv [1]
  49. except (IndexError, ValueError):
  50. # no device number on the command line, assume we want the 1st device
  51. device = 0
  52.  
  53. if len (sys.argv) == 1:
  54. # no argument on the command line, try to use the camera
  55. capture = highgui.cvCreateCameraCapture (device)
  56. else:
  57. # we have an argument on the command line,
  58. # we can assume this is a file name, so open it
  59. capture = highgui.cvCreateFileCapture (sys.argv [1])
  60.  
  61. # check that capture device is OK
  62. if not capture:
  63. print "Error opening capture device"
  64. sys.exit (1)
  65.  
  66. # capture the 1st frame to get some propertie on it
  67. frame = highgui.cvQueryFrame (capture)
  68.  
  69. # get size of the frame
  70. frame_size = cv.cvGetSize (frame)
  71.  
  72. # get the frame rate of the capture device
  73. fps = highgui.cvGetCaptureProperty (capture, highgui.CV_CAP_PROP_FPS)
  74. if fps == 0:
  75. # no fps getted, so set it to 30 by default
  76. fps = 30
  77.  
  78. # create the writer
  79. writer = highgui.cvCreateVideoWriter ("captured.mpg", MPEG1VIDEO,
  80. fps, frame_size, True)
  81.  
  82. # check the writer is OK
  83. if not writer:
  84. print "Error opening writer"
  85. sys.exit (1)
  86.  
  87. while 1:
  88. # do forever
  89.  
  90. # 1. capture the current image
  91. frame = highgui.cvQueryFrame (capture)
  92. if frame is None:
  93. # no image captured... end the processing
  94. break
  95.  
  96. # write the frame to the output file
  97. highgui.cvWriteFrame (writer, frame)
  98.  
  99. # display the frames to have a visual output
  100. highgui.cvShowImage ('Camera', frame)
  101.  
  102. # handle events
  103. k = highgui.cvWaitKey (5)
  104.  
  105. if k % 0x100 == 27:
  106. # user has press the ESC key, so exit
  107. break
  108.  
  109. # end working with the writer
  110. # not working at this time... Need to implement some typemaps...
  111. # but exiting without calling it is OK in this simple application
  112. #highgui.cvReleaseVideoWriter (writer)
  113.  

python各种实用代码片段 zz

python各种实用代码片段 zz
发信站: 水木社区 (Tue Oct  9 10:45:59 2007), 转信

zzfrom: http://www.wujianrong.com/archives/2007/07/python_12.html

1. 各种实用代码片段
1.1. 正则表达式使用
###########################################################
特殊字符:
###########################################################
   "."      匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
   "^"      匹配输入字符串的开始位置。
   "___FCKpd___0quot;      匹配输入字符串的结束位置。
   "*"      匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及"zoo"。 * 等价于{0,}。 Greedy means 贪婪的
   "+"      匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
   "?"      匹配前面的子表达式零次或一次(贪婪的)
   *?,+?,?? 前面三个特殊字符的非贪婪版本
   {m,n}    最少匹配 m 次且最多匹配 n 次(m 和 n 均为非负整数,其中m <= n。)
   {m,n}?   上面表达式的非贪婪版本.
   "\\"      Either escapes special characters or signals a special sequence.
   []       表示一个字符集合,匹配所包含的任意一个字符
            第一个字符是 "^" 代表这是一个补集
   "|"      A|B, 匹配 A 或 B中的任一个
   (...)    Matches the RE inside the parentheses(圆括号).(匹配pattern 并获取这一匹配)
            The contents can be retrieved(找回) or matched later in the string.
   (?iLmsux) 设置 I, L, M, S, U, or X 标记 (见下面).
   (?:...)  圆括号的非成组版本.
   (?P<name>...) 被组(group)匹配的子串,可以通过名字访问
   (?P=name) 匹配被组名先前匹配的文本(Matches the text matched earlier by the
group named name.)
   (?#...)  注释;被忽略.
   (?=...)  Matches if ... matches next, but doesn't consume the
string(但是并不消灭这个字串.)
   (?!...)  Matches if ... doesn't match next.

The special sequences consist of "\\" and a character from the list
below.  If the ordinary character is not on the list, then the
resulting RE will match the second character.
   \number  Matches the contents of the group of the same number.
   \A       Matches only at the start of the string.
   \Z       Matches only at the end of the string.
   \b       Matches the empty string, but only at the start or end of a word
                                       匹配一个空串但只在一个单词的开始或者结束的地方.匹配单词的边界
   \B       匹配一个空串, 但不是在在一个单词的开始或者结束的地方.(匹配非单词边界)
   \d       匹配一个数字字符。等价于 [0-9]。
   \D       匹配一个非数字字符。等价于 [^0-9]。
   \s       匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
   \S       匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
   \w       匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'.
            With LOCALE, it will match the set [0-9_] plus characters defined
            as letters for the current locale.
   \W       匹配\w的补集(匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。)
   \\       匹配一个"\"(反斜杠)

##########################################################
共有如下方法可以使用:
##########################################################
   match    从一个字串的开始匹配一个正则表达式
   search   搜索匹配正则表达式的一个字串
   sub      替换在一个字串中发现的匹配模式的字串
   subn     同sub,但是返回替换的个数
   split    用出现的模式分割一个字串
   findall  Find all occurrences of a pattern in a string.
   compile  把一个模式编译为一个RegexObject对像.
   purge                       清除正则表达式缓存
   escape   Backslash(反斜杠)all non-alphanumerics in a string.

Some of the functions in this module takes flags as optional parameters:
   I  IGNORECASE  Perform case-insensitive matching.(执行大小写敏感的匹配)
   L  LOCALE      Make \w, \W, \b, \B, dependent on the current locale.
   M  MULTILINE   "^" matches the beginning of lines as well as the string.
                  "___FCKpd___0quot; matches the end of lines as well as the string.
   S  DOTALL      "." matches any character at all, including the newline(换行符).
   X  VERBOSE     Ignore whitespace and comments for nicer looking RE's.
   U  UNICODE     Make \w, \W, \b, \B, dependent on the Unicode locale.

This module also defines an exception 'error'.

compile(pattern, flags=0)
返回一个模式对像
Compile a regular expression pattern, returning a pattern object.

escape(pattern)
Escape all non-alphanumeric characters in pattern.

findall(pattern, string)
如果出现一个或多个匹配,返回所有组的列表;这个列表将是元组的列表。
空匹配也在返回值中
Return a list of all non-overlapping(不相重叠的) matches in the string.
If one or more groups are present in the pattern, return a
list of groups; this will be a list of tuples if the pattern
has more than one group.
Empty matches are included in the result.

finditer(pattern, string)
返回一个指示器(iterator);每匹配一次,指示器返回一个匹配对像。
空匹配也在返回值中
Return an iterator over all non-overlapping matches in the
string.  For each match, the iterator returns a match object.
Empty matches are included in the result.

match(pattern, string, flags=0)
返回一个匹配的对像,如果没有匹配的,返回一个None
Try to apply the pattern at the start of the string, returning
a match object, or None if no match was found.

purge()
Clear the regular expression cache

search(pattern, string, flags=0)
返回一个匹配的对像,如果没有匹配的,返回一个None
Scan through string looking for a match to the pattern, returning
a match object, or None if no match was found.

split(pattern, string, maxsplit=0)
返回一个包含结果字串的列表
Split the source string by the occurrences of the pattern,
returning a list containing the resulting substrings.

sub(pattern, repl, string, count=0)
返回一个字串,最左边被不重叠的用"repl"替换了。
Return the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl

subn(pattern, repl, string, count=0)
返回一个包含(new_string, number)的2元组;number是替换的次数
Return a 2-tuple containing (new_string, number).
new_string is the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in the source
string by the replacement repl.  number is the number of
substitutions that were made.

template(pattern, flags=0)
返回一个模式对像
Compile a template pattern, returning a pattern object

_______________________________________________
python-chinese list
python-chinese@lists.python.cn
http://python.cn/mailman/listinfo/python-chinese

{PyRe}
1.2. 自动检查md5sums
"       From: steve <lau.siyuan@gmail.com>
Toggle line numbers Toggle line numbers Toggle line numbers
   1 #! /usr/local/bin/python
   2
   3 import commands
   4 file = raw_input("Enter the filename: ")
   5 sum = raw_input("Enter the md5sum: ")
   6 md = "md5sum " + file
   7 print md
   8 check = str(commands.getoutput(md))
   9 checksum = sum + "  " + file
  10 #print checksum
  11 print check
  12 if check == checksum: print "Sums OK"
  13 else: print "Sums are not the same!"
1.3. 提取网页中的超链接
Toggle line numbers Toggle line numbers Toggle line numbers
   1 r='<a(?:(?:\\s*.*?\\s)|(?:\\s+))href=(?P<url>\S*?)(?:(?:\\s.*>)|(?:>)).*?</a>'
   2 compile(r).findall(a)
"       这个是hoxide和天成讨论出来的方法,用来提取网页中的超链接.
1.4. 解决在 Python 中登录网站的问题
刚刚看了xyb的代码,有点启发。
写了一小段试了以下,可以登录了。呵呵。
import httplib
import urllib
user=?
pwd=?
params=urllib.urlencode({"Loginname":user,"Loginpass":pwd,"firstlogin":1,"option":"登入论坛"})
headers={"Accept":"text/html","User-Agent":"IE","Content-Type":"application/x-www-form-urlencoded"}
website="www.linuxforum.net"
path="/forum/start_page.php"
conn=httplib.HTTPConnection(website)
conn.request("POST",path,params,headers)
r=conn.getresponse()
print r.status,r.reason
data=r.read()
print data
conn.close()

不知从form submit数据和直接提交request有些什么区别?


"       中国Linux论坛
"       由xyb总结:PythonClientCookie
1.5. 浮点数的输出格式
>>> a=6200-6199.997841
>>> a
0.0021589999996649567
>>> print "%f"%a
0.002159
>>> import fpformat
>>> fpformat.fix(a, 6)
'0.002159'
>>> print fpformat.fix(a, 6)
0.002159
>>> print "%.6f"%a
0.002159
>>> print "%.7f"%a
0.0021590
>>> print "%.10f"%a
0.0021590000
>>> print "%.5f"%a
0.00216

1.6. 怎么下载网络上的一张图片到本地
>知道了一张图片的URL >比如http://www.yahoo.com/images/logo.gif >想将它下载到本地保存应该怎么实现?
Toggle line numbers Toggle line numbers Toggle line numbers
   1 urllib.urlretrieve(url, filename)
---Limodou
1.7. 使用locale判断本地语言及编码
from::limodou的学习记录
在支持unicode软件中,经常需要在不同的编码与unicode之间进行转换。
那么对于一个本地文件的处理,首先要将其内容读出来转换成unicode编码,在软件中处理完毕后,再保存为原来的编码。
如果我们不知道文件的确切编码方式,可以使用默认的编码方式。那么我们可以使用locale模块来判断默认编码方式。
>>>import locale
>>>print locale.getdefaultlocale()
('zh_CN', 'cp936')

可以看出,我的机器上默认语言是简体中文,编码是GBK。
1.8. __new__的使用
from: 中国Linux论坛 -rings
new
new
是python里object的方法。如果你要重载new,那么你需要继承object。 new是类方法。他不带self参数。
new和init是不一样的。init带 self参数。所以他是在对象已经被构造好了以后被调用的。而如果你要在对象构造的时候
做一些事情,那么就需要使用new。new的返回值必须是对象的实例。 new一般在 一些模式里非常有用。我们看一个例子。
这个例子是《thinking in python》里的一个Singleton例子
class OnlyOne(object):
    class __OnlyOne:
        def __init__(self):
            self.val = None
        def __str__(self):
            return ′self′ + self.val
            
        instance = None
        def __new__(cls): # __new__ always a classmethod
            if not OnlyOne.instance:
            OnlyOne.instance = OnlyOne.__OnlyOne()
            return OnlyOne.instance
        def __getattr__(self, name):
            return getattr(self.instance, name)
        def __setattr__(self, name):
            return setattr(self.instance, name)

x = OnlyOne()
x.val = 'sausage'
print x
y = OnlyOne()
y.val = 'eggs'
print y
z = OnlyOne()
z.val = 'spam'
print z
print x
print y

我们可以看到OnlyOne从object继承而来。
如果你不继承object,那么你的 new就不会在构造的时候来调用。
当x = OnlyOne()的时候,其实就是调用new(OnlyOne), 每次实例化OnlyOne 的时候都会调用。
因为他是类方法。
所以这段代码就是利用这个特性来实现Singleton的。
因为不管构造多少对象,都要调用new.
那么在OnlyOne里保持一个类的属性, instance.
他代表嵌套的_OnlyOne的实例。
所以,对于他,我们只构造一次。
"       以后每次构造的时候都是 直接返回这个实例的。
所以,在这里, x,y,z 都是同一个实例。
这个方法和典型的用C++ 来实现 Singleton的道理是一样的。
1.9. traceback 的处理
from::Limodou的学习记录
trackback在 Python 中非常有用,它可以显示出现异常(Exception)时代码执行栈的情况。 但当我们捕捉异常,一般是自已的出错处理,因此代码执行栈的信息就看不到了,如果还想显 示的话,就要用到traceback模块了。
这里只是简单的对traceback模块的介绍,不是一个完整的说明,而且只是满足我个人的要求, 更详细的还是要看文档。
打印完整的traceback
让我们先看一个traceback的显示:
>>> 1/0

Traceback (most recent call last):
  File "", line 1, in -toplevel-
    1/0
ZeroDivisionError: integer division or modulo by zero

可以看出 Python 缺省显示的traceback有一个头:第一行,出错详细位置:第二、三行, 异常信息:第四行。也就是说分为三部分,而在traceback可以分别对这三部分进行处理。 不过我更关心完整的显示。
在traceback中提供了print_exc([limit[, file]])函数可以打印出与上面一样的效果。 limit参数是限定代码执行栈的条数,file参数可以将traceback信息输出到文件对象中。缺省的话是输出到错误输出中。举例:
>>> try:
    1/0
except:
    traceback.print_exc()
 
Traceback (most recent call last):
  File "", line 2, in ?
ZeroDivisionError: integer division or modulo by zero

当出现异常sys.exc_info()函数会返回与异常相关的信息。如:
>>> try:
    1/0
except:
    sys.exc_info()

(<class exceptions.ZeroDivisionError at 0x00BF4CC0>,
<exceptions.ZeroDivisionError instance at 0x00E29DC8>,
<traceback object at 0x00E29DF0>)

sys.exc_info()返回一个tuple,异常类,异常实例,和traceback。
print_exc()是直接输出了,如果我们想得到它的内容,如何做?使用 format_exception(type, value, tb [,limit]),type, value, tb分别对应 sys.exc_info()对应的三个值。如:
>>> try:
    1/0
except:
    type, value, tb = sys.exc_info()
 print traceback.format_exception(type, value, tb)

['Traceback (most recent call last):\n', '  File "", line 2, in ?\n',
'ZeroDivisionError: integer division or modulo by zero\n']

这样,我们知道了format_exception返回一个字符串列表,这样我们就可以将其应用到我们的程序中了。
1.10. os.walk()的用法, 修改cvsroot
"       重装系统, windows盘符大乱, 原来是'e:\cvsroot'现在变为'g:\cvsroot', 众多由cvs管理的目录无法正常工作了. python脚本出动:
Toggle line numbers Toggle line numbers Toggle line numbers
   1 import os
   2 from os.path import join, getsize
   3 import sys
   4
   5 print sys.argv[1]
   6 for root, dirs, files in os.walk(sys.argv[1]):
   7     if 'CVS' in dirs:
   8         fn = join(root+'\CVS', 'ROOT')
   9         print root+' :', fn
  10         #dirs.remove('CVS')  # don't visit CVS directories
  11         f = open(fn,'r')
  12         r = f.read()
  13         print r
  14         f.close()
  15         if r.startswith('e:\cvsroot'):
  16             open(fn, 'w').write('g:\cvsroot')
  17             f = open(fn,'r')
  18             r = f.read()
  19             print r
  20             f.close()
2. Python多进程处理之参考大全
* PyCourse --from
http://blog.huangdong.com (即将成为历史的HD的个人blog,大家默哀)  
3. 将你的Python脚本转换为Windows exe程序
from:: http://blog.huangdong.com (即将成为历史的HD的个人blog,大家默哀)  
将Python的脚本变为一个可以执行的Windows exe程序可能的好处会说出很多,我最喜欢的则是它会让你写的程序更像是一个"程序"罢。但是,凡事有利就有弊,这样必然会让python的一些好处没有了。
你可以从这里找到py2exe的相关信息,可以在这里下载到py2exe-0.4.2.win32-py2.3.exe安装包。 但是它的使用也还是比较麻烦的,需要你自己手工的写一个小的脚本,就像这样:
Toggle line numbers Toggle line numbers Toggle line numbers
   1 # setup.py
   2 from distutils.core import setup
   3 import py2exe
   4
   5 setup(name="myscript",
   6 scripts=["myscript.py"],
   7 )
再通过python的执行:
python setup.py py2exe

来使用。更多的信息上它的网站看罢。
4. 使用 WinAPI 的例子
"       /PyWinApi -- 简单范例
5. 在函数中确定其调用者 !
"       AlbertLee
"       /PyCallParent
6. Python哲学--内省的威力
"       AlbertLee
"       Xie Yanbo 引发
"        
"       Remember, Python comes with batteries included!
"       PyBatteriesIncluded -- 使用内省的功能,获得丰富的信息
7. 在正则表达式中嵌入注释时的陷阱
如下代码所示:
s = 'create table testtable'
>>> p =  r"""
^create\ table   # create table
\s*                 # whitespace
([a-zA-Z]*)      # table name
$                   # end
"""
>>> re.compile(p, re.VERBOSE).match(s).groups()
('testtable',)
>>>

如果在create和table之间没有那个转义的空格,即\ ,在re.VERBOSE 的时候,就会将那个空格忽略掉,因此变成是匹配createtable了,这样 他就会匹配不到了
8. python写的数字转中文的程序
"       源于qq上Jaina(16009966)的提问. 花了一个晚上实现了一下, 基本想法是4位为一个断, 用conv4转换, 然后再用conv组合之. 程序在Windows2003, python2.4下调试通过. 注意编码问题.
Toggle line numbers Toggle line numbers Toggle line numbers
   1 # coding:utf-8
   2
   3 UUNIT=[u'', u'十' , u'百' , u'千']
   4 BUINT = [u'', u'万', u'亿', u'万亿' , u'亿亿']
   5 NUM=[u'零',u'一',u'二', u'三', u'四', u'五' , u'六', u'七', u'八', u'九']
   6
   7 def conv4(num, flag=False):
   8    ret = u''
   9    s = str(num)
  10    l = len(s)
  11    assert(len(s) <= 4)
  12    if flag and len(s)<4:
  13       ret = ret + NUM[0]
  14    for i in xrange(l):
  15       if s[i] != '0':
  16          ret = ret + NUM[int(s[i])]+UUNIT[l-i-1]
  17       elif s[i-1] != '0':
  18          ret = ret + NUM[0]
  19    return ret
  20
  21 def conv(num):
  22    ss = str(num)
  23    l = len(ss)
  24    j = l / 4
  25    jj = l % 4
  26    lss = [ss[0:jj] for i in [1] if ss[0:jj]] \
       + [ss[i*4+jj:(i+1)*4+jj] for i in xrange(j) if ss[i*4+jj:(i+1)*4+jj] ]
  27    print lss
  28    ul = len(lss)
  29    ret = u''
  30    zflag = False
  31    for i in xrange(ul):
  32       bu = BUINT[ul-i-1]
  33       tret = conv4(int(lss[i]), flag = i)
  34       if tret[-1:] == NUM[0]:
  35          tret = tret[:-1]
  36       if tret:
  37          print zflag , (tret+bu).encode('mbcs')
  38          if zflag and tret[0] != NUM[0] :
  39             ret = ret + NUM[0] +tret+bu
  40          else:
  41             ret = ret + tret+bu
  42          zflag = False
  43       else:
  44          zflag = True
  45    return ret
  46
  47 if __name__ == '__main__':
  48    #print conv(11111)
  49    print conv(103056).encode('mbcs')
  50    print conv(101000).encode('mbcs')
  51    print conv(1200999100000000010).encode('mbcs')

(转载)





用 Eclipse 和 Ant 进行 Python 开发

用 Eclipse 和 Ant 进行 Python 开发

用 Eclipse IDE 和 Apache Ant 构建工具进行 Python 开发

developerWorks
文档选项

未显示需要 JavaScript
的文档选项


将打印机的版面设置成横向打印模式

打印本页

将此页作为电子邮件发送

将此页作为电子邮件发送


级别: 初级

Ron Smith (ron.smith@rpstechnologies.net), 负责人

2004 年 6 月 01 日

Python
是一种非常灵活强大的动态脚本编程语言,具有完整的面向对象特性。众多的支持者指出,Python
语言与其他语言相比能更快更有效地表达出他们的意图。但是从 Java 技术™ 或 Microsoft® .NET 刚刚转到 Python
的人会发现,功能丰富而精致的 IDE 和开发工具都不见了。那些开发人员可以从他们熟悉的 Java
开发工具中找到解决方案。本文着重介绍了如何使用基于 Java 技术的流行开发工具 Eclipse 和 Ant 进行 Python 开发。



简介



年以来, Java 语言和 Python 阵营之间一直存在大量的异花授粉现象。在这方面作出突出表率的可能是 Jython。这是一个纯粹用
Java 实现的 Python 运行时环境。按照这一说法,您将研究如何用 Eclipse IDE 和 Ant 构建与部署工具实现 Python
开发。Eclipse 和 Ant 是非常流行的工具,它们特性丰富、可扩展性强、而且开放源代码;Python 也具有相同的品质。PyDev 和
PyAntTasks 分别是 Eclipse 和 Ant 的扩展,有了它们就可能用这些 Java 工具开发
Python。本文从下载安装所需的工具与扩展开始讲起。为了解释如何在 Python 开发中使用 Eclipse 和 Ant,我将用实际的
Python 代码例子读取 RSS 资源。


本文不会涉及 Eclipse、Ant、Python 的细节。有关这些话题的深入讨论,请参阅
参考资料 一节中的链接。


Python 支持情况



文用到的软件都在 CPython 2.3 下测试过。除了几个异常情况之外,应该也能在 Jython 中运行。特别需要指出,PyDev
调试器目前不支持 Jython。另一个区别是通过 Jython 执行的脚本在从 PyDev
中运行之后就转入交互模式,这样就必须手动杀死。PyDev 编辑器与 Jython 的源代码兼容,Python Ant 任务除 py-doc
任务之外也和 Jython 兼容。






回页首


使用 Eclipse 进行 Python 开发


Eclipse 概述


Eclipse
是一个 Java 技术集成开发环境,由 IBM 开发,并开放其源代码。它是 IBM 商业软件 WebSphere Application
Development 环境以及其他多种工具的基础。Eclipse 的开发社区非常活跃,他们不仅开发 Eclipse 本身,还开发大量的插件供
Eclipse 使用。有关 Eclispe 和 Eclipse 插件的 Web 站点,请参阅 参考资料 一节中的链接。尽管从传统上讲 Eclipse 是一种 Java 开发工具,但是一些插件的存在使得在 Eclipse 中开发其他语言的程序成为可能,如 C/C++、Python 和 Perl。



Eclipse 中,源代码被组织到项目(project)中。项目可以加载、卸载和导入。Eclipse
用户界面的结构划分为视图(View)与编辑器(Editor)。视图与编辑器的例子包括:源代码大纲视图、Java 源代码编辑器、Python
源代码编辑器和文件系统导航视图。Eclipse 用户界面中最关键的隐含概念就是 视角(perspective)。视角是通常在执行某种类型活动时一起使用的一组视图。Eclipse
中的标准视角包括:Debug、Java Browsing、Java、Java Type Hierarchy、Plug-in
Development、CVS Repository Exploring、Resource 和
Install/Update。目前还不存在单独的 Python 视角。在进行 Python 开发时,我通常使用 Resource 视角和
Debug 视角。


安装 PyDev


首先,从 Eclipse Web 站点上下载 Eclipse(请参阅
参考资料 一节中的链接),并根据您的平台,按照下面的安装指南安装 Eclipse:


Eclipse 的更新机制使 PyDev 插件的安装更加容易。从 Eclipse 中选择
Help > Software Updates > Update Manager
启动 Install/Update 视角。在左下角的 Feature Updates 视图中,将 PyDev 插件更新站点作为新的 Site
Bookmark 添加到“Sites to Visit”文件夹下。Eclipse 的 PyDev 更新站点 URL 为
http://pydev.sf.net/updates/。现在,Feature Updates 编辑器中应该显示出“PyDev”这一特性。在
Feature Updates 编辑器中,展开 PyDev > Other,选择其中显示的 PyDev 特性(至少应该是 0.4.1)。然后选择 “Install Now”安装该特性。Eclipse 将下载 PyDev 插件,并将其安装到 Eclipse 中。


导入样例项目


为访问本项目中使用的样例代码,可先下载 zip 文件(请参阅
参考资料一节),在文件系统中展开该 zip 文件,然后将其中的项目导入 Eclipse。导入项目的方法是先切换到 Resource 视角,选择
File > Import,再选择“Existing Project into Workspace”,然后选择您展开 zip 文件的位置。这时,Navigator 视图中应该出现 feedParserTest 项目。



样例项目中已经包含了 Fead Parser 通用资源解析库,该库按 Python 开放源代码许可协议发布。有关 Feed Parser 项目 Web 网站的链接,请参阅
参考资料 一节。






回页首


PyDev 漫游



现在开始学习如何通过已导入的项目了解 PyDev 的特性。PyDev 正处于开发过程中,但已经是非常高效的 Python 开发环境。现在的 PyDev 主要包括以下特性:


  • 包含 Python 语法高亮显示特性的 Python 编辑器。
  • 进行 Python 语法分析,并在 Python 编辑器和 Tasks 视图中高亮显示错误。
  • 可将制表符转换成空格的选项。
  • Outline 视图显示导入的库、类以及函数。
  • 终端视图中的 Python 堆栈跟踪信息可超链接到源代码中。
  • 源代码内部的超链接;同一模块内的导入和函数调用可通过超链接进行导航。
  • 从 Navigator 视图中运行 Python 脚本的能力。
  • 调试器支持断点、代码单步执行以及显示变量的值。

PyDev 选项窗口



通过
Window > Preferences,并选择 PyDev(请参阅图 1),便可访问 PyDev 选项。第一组选项可以改变 PyDev 在源代码中处理制表符的方式,还可以改变语法元素的颜色。




图 1. PyDev 选项窗口

PyDev 选项窗口


设置 Python 解释器



PyDev Debug 选项可以选择 Python 解释器,供执行 Python 代码时使用。如果 PyDev 无法找到 Python 解释器,或者想使用别的解释器,可在此设置(请参阅图 2)。




图 2. PyDev Debug 选项

PyDev Debug 选项


处理源代码



我的大部分 Python 工作都是在 Resource 视角中完成的。使用方法是先切换到 Resource 视角,然后在左上角的
Navigator 视图中双击 feedParserTest/src/feedparserTest/FeedparserTest.py
文件。Python 编辑器打开该文件,对 Python 语法进行解析,完成设置颜色和语法检查的工作(请参阅图 3)。




图 3. Python 编辑器

Python 编辑器



如果源代码中有任何错误,则显示在右下角的 Tasks 视图中显示出来。双击 Tasks 视图中的错误,便可找到那条讨厌的代码行。


Outline
视图在左下角,其中用一种便于浏览的结构显示出当前正在编辑的文件。导入的库、类、函数全都显示出来,通过双击 Outline
视图中的项目,便可以实现导航。PyDev 在编辑 Python 文件的过程中对齐进行预先解析的工作,同时更新 Outline
视图,执行语法检查,并用不同颜色显示语法元素。


编辑器的特性



PyDev 0.4 版在 Python 源代码编辑器中为函数和导入库加入了超链接的特性。如果在越过某项导入或函数调用(必须在
PYTHONPATH 目录中)的同时按下 Control 键,PyDev 就能显示出一个超链接,这样您可以在导入库或函数的源代码之间导航。请注意,为了在您自己的源代码中跨模块使用该特性(从一个模块链接到另一个模块),必须修改
PYTHONPATH 环境变量,在其中加入这些模块,这样 PyDev 就可以找到它们了。



人们已经开始将一些优异的源代码编辑特性加入最新版本的 PyDev 中,其中就包括代码块注释与取消注释,以及代码左右移位(请参阅图 4)。




图 4. PyDev 编辑器的其他特性

PyDev 编辑器的其他特性


运行 Python 脚本



如果不能执行代码,那么 IDE 也不是太有用。为执行 Python 代码,可从 Navigator 视图中选择 feedparser.py 文件,用右键点击,然后选择
Python > Run。随后会显示 Python 的启动配置窗口(请参阅图 5)。




图 5. Python 启动配置

Python 启动配置


Python
启动配置窗口中可以定义脚本执行的当前目录,传递给脚本的参数,以及用哪一个 Python 解释器运行脚本。feedparser.py 以一个
RSS URL 作为参数,所以可在参数字段中填入 URL,如
http://www.ibm.com/developerworks/news/dw_dwtp.rss。其余的缺省定义就可以了,所以单击 Run



脚本执行时输出信息显示在 Console 窗口中。如果有错误出现,Console 窗口中将显示堆栈跟踪信息,其中的每一行都可以通过超链接找到 Python 源代码。


Python 调试器


Python
调试器是最近才加入 PyDev 插件中的。要使用调试器,可在 Python 编辑器中想中断的代码行的左侧点击,设置断点。在图 6 中,我在
feedparser.py 的 1830 行处设置了断点。然后在 Navigator 视图中选择这个 Python
模块,点击右键,选择“Python > Debug...”。这时将显示与前面相似的一个启动配置窗口。点击 Debug 进入 Debug 视角,同时启动调试器。




图 6. Python 调试器

Python 调试器



左上角的 Debug 视图显示当前正在执行的进程和线程,右上角的 Variables 视图显示当前运行域中的所有变量,Python
编辑器会显示调试器目前停在哪条语句上,同时所有的输出信息都显示与 Console 视图中。调试器可以通过 Debug 视图底部的按钮或 Run
菜单进行控制。


其他 Eclipse 特性



Eclipse 及其插件还具备很多其他的特性,可应用于 Python 开发中,如 XML 编辑器、UML 编辑器(不过大多数是以 Java 代码为中心),还有资源控制方面的插件。目前 Eclipse 插件站点上列出的插件几乎有 500 个(请参阅
参考资料 一节中的相关链接)。我将着重介绍一个对很多 Python 开发人员都特别有用的插件:Eclipse 发行版中已经包括的 CVS 插件,不过不会讨论细节内容。



Eclipse 中包括特性丰富的集成 CVS:


  • 支持 SSH、pserver、ext 等连接方法。
  • 基本 CVS 命令的支持:检出项目、提交变更、更新、向.cvsignore 中增加文件或模式等等。
  • 文件合并查看。
  • 在源代码控制中实现对文件不同之处的比较。
  • 项目同步,并用资料库显示出删除和新增的内容。


还可以通过提供其他插件来支持其他源代码控制系统,如 ClearCase、Subversion、Visual SourceSafe 等。






回页首


在 Eclipse 中使用 Python 的交互式 shell



Python 解释器支持 Python 代码的交互式执行。这种方式对于调试一段代码是非常有用的,因为不用把代码放进 Python 脚本中并执行脚本了。同时,Python 解释器的交互模式可以很容易地集成到 Eclipse 中。



要增加对 Python 交互式执行的支持,可通过
Run > External Tools > External Tools
增加一个 External Tool 启动程序。这时将打开 External Tool 启动程序配置窗口。在 Configurations
列表中选择“Program”,然后点击“New”创建一个新的配置。将该配置命名为诸如 "pythonInteractive" 之类,然后设置
Location,令其指向您的 Python 解释器,接着,将 "-i" 作为唯一的参数传递进来(请参阅图 7)。



在 Common 选项卡下,选中复选框,使该配置在 External Tools 收藏夹菜单中显示出来。




图 7. Python 交互方式配置

Python 交互方式配置



要运行刚刚在 Eclipse 中创建的启动器,可选择
Run > External Tools > pythonInterpreter。Python 解释器的输出显示在 Console 视图中。Console 中可输入 Python 命令并执行,就像从命令行中执行 Python 一样。为导入并在交互模式下使用模块,您需要将模块的位置增加到
PYTHONPATH 环境变量中。



在 Eclipse Console 中执行 Python 与用命令行执行的不同之处在于,无法启用命令历史特性(通过向上和向下的方向键实现),因为 Eclipse Console 会自己解释这些键。






回页首


在 Python 开发中使用 Ant



Python 会在它需要的时候自动编译模块。这意味着 Python 开发人员通常不必显式地对模块进行编辑。即便如此,有时候手工编译 Python 代码还是很有用的,同时,构建和部署过程中还有很多其他方面的内容可以自动化实现。这也正是构建工具的用武之地。



我将着重介绍来自 Java 编程世界中的 Apache Ant,这个工具可大量应用在 Python 开发中。Apache Ant 是 Java
编程领域内事实上的标准构建工具。它更加轻便,与 Java 技术结合得更好,可用于替代其他的构建工具。Ant 可以在支持 Java
编程语言的任何一种平台上运行。尽管我们需要的大多数构建特性 Ant 都已经提供了,但如果要将 Ant 用做 Python
构建工具,还是需要有一些关键的与 Python 相关的特性。我已经开发了若干定制的 Ant 插件(用 Ant 的行话讲叫做
task),可提供构建 Python 时需要的特定于 Python 的特性。


Ant 用 XML 作为描述构建的格式。build
文件组织为需要执行的目标。每一个目标都可能依赖于其他的目标。Ant
将根据您所请求执行的目标,以及一组依赖目标,来执行任何需要的目标。每一个目标都可能包含任意数量的 Ant 任务,而由 Ant
任务实际执行目标的工作。Ant 有很多内置的任务,可以完成诸如编译 Java
代码、生成文档、操纵文件和目录,同时第三方又提供了很多附加的任务。


安装 Python Ant 库



我将通过为 feedparser 项目创建构建脚本来介绍 Ant 构建脚本和 Python Ant 任务的基础知识。为了使用 Python Ant 任务,您需要下载并安装包含这些任务的 Java 库。首先,从
参考资料
一节中列出的 URL 中下载 Python Ant 任务库(pyAntTasks.jar)。然后,将 JAR 文件拷贝到 Eclipse 的
Ant 插件下的 lib 目录中。这应该是 Eclipse 安装目录下形如 plugins/org.apache.ant_1.5.3
的子目录。



Python Ant 任务库拷贝完毕之后,必须在 Eclipse 中启用库。选择
Window > Preferences,然后选择
Ant > Runtime
将 Ant Home Entries 展开,其中可看到 Eclipse 使用的库(JAR 文件)列表。选择“ Add JAR”,然后从
Eclipse Ant 插件的 lib 目录中选择 Python Ant JAR 文件,就可以将刚刚拷贝的 Python Ant JAR
文件加入库列表中(请参阅图 8)。




图 8. 向 classpath 中加入 Python Ant 任务

向 classpath 中加入 Python Ant 任务



您现在应该能够创建和运行包含 Python 任务的 Ant 构建脚本了。下面进入构建脚本内部!


创建构建脚本



我将逐步介绍如何创建一个简单的 Python 构建脚本(请参阅清单 1)。完整的构建脚本 build.xml 可从 feedParserTest 项目的顶层目录中找到。



清单 1. 用于编译 Python 源代码的构建脚本片断

<project name="feedParserTest" default="compile">
<taskdef resource="pyAntTasks.properties"/>
<property name="src.dir" value="src"/>
<target name="compile">
<py-compile dir="${src.dir}" pythonpath="${src.dir}" optimize="0"/>
</target>
</project>



先介绍一个只编译 Python 样例代码的构建脚本。<project> 标签总是构建脚本的根标签。<taskdef> 标签声明在整个构建脚本中使用的 Python 任务。在构建脚本的底部,可以定义
compile 目标。目标元素内部是
compile
运行期间执行的任务。特别的是 py-compile 任务,它负责从 src 目录开始,编译所有的 Python
代码。该任务会递归遍历所有的子目录,并编译所有的 Python 模块。脚本中没有采用将 src
目录硬编码到调用之处的方式,而是在构建脚本中定义了称为 src.dir 的属性。然后,在需要使用这个目录名的时候,就可以通过 ${src.dir} 来引用。



要运行构建脚本,可从 Eclipse 中打开它。Eclipse 具有内置的 Ant 构建脚本编辑和浏览功能。Outline 视图可以显示出构建脚本的结构。在 Navigator 视图中,选择该构建脚本,用右键点击,然后选择“Run Ant...”。选择
compile 目标,然后点击“Run”。构建脚本执行过程中的输出信息应该显示在 Console 视图中,表示运行成功。


Python 脚本执行任务



接下来将向构建脚本中加入新的目标,用于执行 Python 脚本(请参阅清单 2)。在本例中,可以将 RSS URL 作为参数来执行 feedparser.py 脚本。



清单 2. 运行 feedparser 脚本的构建脚本片断

  <target name="run.feedparser" depends="compile">
<py-run script="src/feedparser/feedparser.py" pythonpath="${src.dir}" optimize="0">
<arg value="http://www.ibm.com/developerworks/news/dw_dwtp.rss">
</py-run>
</target>



上面的目标以 RSS URL 为唯一的参数来执行 feedparser.py 脚本。该目标声明为依赖于
compile 目标,所以后者将首先执行。实际上这一步并不是很必要,因为 Python 会根据需要自动编译源代码。如果您执行
run.feedparser 目标,就会运行 feedparser.py 脚本,同时将 RSS 的内容输出到 Console 中。


Python 文档任务



Python 的 API 文档编制机制与 Java 技术中的 JavaDoc 系统类似,称为 PyDoc。在构建脚本中加入清单 3 中列出的如下 XML 片断,可为所有的 Python 模块生成 PyDoc。



清单 3. 用于生成 PyDoc 的构建脚本片断

 1:  <property name="pydoc.dir" value="pydoc"/>
2:
3: <target name="init">
4: <mkdir dir="${pydoc.dir}"/>
5: </target>
6:
7: <target name="pydoc" depends="init,compile">
8: <py-doc pythonpath="${src.dir}" destdir="${pydoc.dir}">
9: <fileset dir="${src.dir}">
10: <include name="**/*"/>
11: </fileset>
12: </py-doc>
13: </target>




从对上述 pydoc 目标的解析可看出,第 7 行声明了目标名称,并指出它依赖于
init
compile 目标。这意味着在运行 pydoc 目标之前,Ant 必须保证
init
compile 目标已经运行,如果没有,则首先运行这两个目标。



pydoc 目标所依赖的
init 目标在第 3 至第 5 行定义。
init 目标仅仅创建了一个存放 PyDoc API 文档文件的目录。如前所述,要为所生成文档的保存位置定义一个属性,名为 pydoc.dir。



第 8 行开始是 py-doc 任务。如前所述,您传入生成 pydoc 过程中所使用的
PYTHONPATH
destdir 属性告诉 py-doc 任务将生成的 HTML 文档输出到何处。



第 9 至第 11 行定义了在生成文档的过程中应该处理哪些 Python 源文件。文件集是 Ant
脚本中通用的结构,可用于定义所操作的一组文件。这是一种很强大的特性,它使您能够通过名字模式、布尔逻辑和文件属性来选择所要操作的文件。Ant
文档中有这方面的完整描述。本例中递归选择了“src”目录下的所有文件。


Python 单元测试任务


Python
中具有标准的单元测试框架(从 Python 2.3 开始。在 Python 2.2 中这只是可选模块),与 Java jUnit
框架十分类似。测试用例的结构与 jUnit
采用相同的方式。每一个待测试的类和模块通常都具有自己的测试类。测试类中包含测试装置(fixture),它们在 setUp 函数中初始化。每一个测试都编写为测试类中的一个独立的测试函数。unittest 框架会在测试函数之间循环往复,先调用
setUp 、再测试函数、然后清除(
tearDown )测试函数。请参阅清单 4 中的样例。



清单 4. Python 单元测试模块

import unittest
from pprint import pprint
import feedparser
class FeedparserTest(unittest.TestCase):
"""
A test class for the feedparser module.
"""

def setUp(self):
"""
set up data used in the tests.
setUp is called before each test function execution.
"""
self.developerWorksUrl = "testData/developerworks.rss"
def testParse09Rss(self):
"""
Test a successful run of the parse function for a
0.91 RSS feed.
"""
print "FeedparserTest.testParse09RSS()"

result = feedparser.parse(self.developerWorksUrl)
pprint(result)
self.assertEqual(0, result['bozo'])

self.assert_(result is not None)
channel = result['channel']
self.assert_(channel is not None)
chanDesc = channel['description']
self.assertEqual(u'The latest content from IBM developerWorks',
chanDesc)

items = result['items']
self.assert_(items is not None)
self.assert_(len(items)> 3)
firstItem = items[0]
title = firstItem['title']
self.assertEqual(u'Build installation packages with
solution installation and deployment technologies',
title)

def tearDown(self):
"""
tear down any data used in tests
tearDown is called after each test function execution.
"""
pass

if __name__ == '__main__':
unittest.main()



上述清单是实现 feedparser 模块基本测试功能的测试类。完整的测试类见 feedParserTest 项目下的 src/feedparserTest/FeedparserTest.py。
setUp 函数负责准备整个测试过程中需要使用的测试装置,在本例中只有测试用的 RSS 文件的目录,测试函数将对其进行解析。
testParse09Rss
是真正的测试函数。这个函数调用 feedparser.parse 函数,传递测试用的 RSS 文件,输出解析结果,并通过 TestCase
类的 assert 函数执行基本的检查统作。如果任何 assert 的求值结果不是真,或是在执行过程中抛出任何异常,unittest
就会报告一次测试失败或错误。最后的两行负责在这个测试类内部运行测试,方法是直接运行该模块即可。



要独立运行该测试类,可以按前面所说的相同方式运行 FeedparserTest.py 模块。在 Eclipse Navigator 视图中选择 FeedparserTest.py,然后通过
Python > Run
运行。此时显示启动配置窗口。除 Base 目录之外,其他都保持缺省值即可。Base 目录必须是 feedParserTest
项目的目录,这样才能在当前目录下找到 RSS 文件(testData/developerworks.rss)。修改 base
目录的设置,然后点击“Run”。输出信息显示在 Console 上。



您也许希望我们编写的所有单元测试都能够作为构建的一部分自动执行。将下面清单 5 所示的构建片断加入构建脚本便可实现。



清单 5. 执行单元测试的构建脚本片断

1:  <target name="tests" depends="compile">
2: <py-test pythonpath="${src.dir}" dir=".">
3: <fileset dir="${src.dir}">
4: <include name="**/*Test.py"/>
5: </fileset>
6: </py-test>
7: </target>



第一行是目标声明,这与其他的脚本相同。第 2 至第 6 行调用 py-test 任务。这部分代码将在“src”目录下查找所有以“Test.py”结尾的所有文件,并运行所有测试。
PYTHONPATH 设置为“src”,测试执行的当前工作目录就是当前目录(‘.’)。



运行目标的方法是先运行构建脚本,再选择执行“tests”目标。该目标将运行所有以“Test.py”结尾的测试用例,本例中仅有 FeadparserTest.py。






回页首


结束语



Eclipse 和 PyDev 插件的结合,以及 Apache Ant 与 Python Ant 任务一起使用,可以为 Python
开发提供完全集成的开发环境和构建/部署工具。这些工具尚在开发过程中,因此要经常查看是否有更新,如果您觉得特别希望看到某种特性,可以卷起袖管自力更
生。




参考资料





关于作者


Ron
Smith 是 RPS Technologies, Inc 的创始人。这是一家软件开发与软件顾问公司,总部位于芝加哥地区。Ron Smith
为客户提供基于 J2EE 的企业应用程序发方面的咨询,同时也在 RPS Technologies 内部开发软件产品。可以通过 ron.smith@rpstechnologies.net与 Ron 联系。








Python少打字小技巧

Python少打字小技巧
发信站: 水木社区 (Fri Jun  8 00:10:37 2007), 转信

Python代码优化--少打字小技巧

说明:增加代码的描述力,可以成倍减少你的LOC,做到简单,并且真切有力
观点:少打字=多思考+少出错,10代码行比50行更能让人明白,以下技巧有助于提高5倍工作效率

1. 交换变量值时避免使用临时变量:(cookbook1.1)

老代码:我们经常很熟练于下面的代码
temp = x
x = y
y = temp

代码一:
u, v, w = w, v, u
有人提出可以利用赋值顺序来简化上面的三行代码成一行

代码二:
u, v = v, u
其实利用Python元组赋值的概念,可更简明 -- 元组初始化 + 元组赋值

2. 读字典时避免判断键值是否存在:(cookbook1.2)
d = { 'key': 'value' }
老代码:
if 'key' in d: print d['key']
else: print 'not find'
新代码:
print d.get('key', 'not find')  

3. 寻找最小值和位置的代码优化:
s = [ 4,1,8,3 ]
老代码:
mval, mpos = MAX, 0
for i in xrange(len(s)):
    if s[i] < mval: mval, mpos = s[i], i
新代码:
mval, mpos = min([ (s[i], i) for i in xrange(len(s)) ])
元组比较的特性,可以方便的写做一行

观点一:用Python编程,需要有“一字千金”的感觉;既然选择了Python,就不要在意单条语句的效率。

上面几点例子很基础,实际中将原始代码压缩1/5并不是不可能,我们之前一个子项目,C++代码270K
重构后Python代码只有67K,当然使用python的日志模块(logging),读写表格文本(csv)等,也功
不可末,最终代码变成原来的1/4,我觉得自己的寿命延长了三倍。。。下面优化几个常用代码:

4. 文件读取工作的最简单表达:

老代码:我们需要将文本文件读入到内存中
line = ''
fp = open('text.txt', 'r')
for line in fp: text += line

代码一:
text = string.join([ line for line in open('text.txt')], '']

代码二:
text = ''.join([ line for line in open('text.txt')])  

代码三:
text = file('text.txt').read()  
新版本的Python可以让你写出比1,2漂亮的代码(open是file的别名,这里file更直观)

5. 如何在Python实现三元式:

老代码:用惯C++,Java,C#不喜欢写下面代码
if n >= 0: print 'positive'
else: print 'negitive'

代码一:该技巧在 Lua里也很常见
print (n >= 0) and 'positive' or 'negitive'
说明:这里的'and'和'or'相当于C中的':'和'?'的作用,道理很简单,因为如果表达式为
真了那么后面的or被短路,取到'positive';否则,and被短路,取到'negitive'

代码二:
print (n >= 0 and ['positive'] or ['negitive])[0]
说明:将两个值组装成元组,即使'positive'是None, '', 0 之类整句话都很安全

代码三:
print ('negitive', 'positive')[n >= 0]
说明:(FalseValue, TrueValue)[Condition] 是利用了 元组访问 + True=1 两条原理

6. 避免字典成员是复杂对象的初始化:(cookbook1.5)
老代码:
if not y in d: d[y] = { }
d[y][x] = 3
新代码:
d.setdefault(y, { })[x] = 3
如果成员是列表的话也一样: d.setdefault(key, []).append(val)

上面六点技巧加以发挥,代码已经很紧凑了,但是还没有做到“没有一句废话”可能有人怀疑真的能
减少1/5的代码么??我要说的是1/5其实很保守,Thinking in C++的作者后来用了Python以后
觉得Python甚至提高了10倍的工作效率。下面的例子可以进一步说明:

例子1:把文本的IP地址转化为整数

说明:需要将类似'192.168.10.214'的IP地址转化为 0x0C0A80AD6,在不用 inet_aton情况下
当C++/Java程序员正为如何进行文本分析,处理各种错误输入烦恼时,Python程序员已经下班:

f = lambda ip: sum( [ int(k)*v for k, v in zip(ip.split('.'), [1<<24, 65536, 256, 1])] )

首先ip.split('.')得到列表['192','168','10','214'],经过zip一组装,就变成
[('192',0x1000000),('168',0x10000),('10',0x100),('214',1)]
接着for循环将各个元组的两项做整数乘法,最后将新列表的值用sum求和,得到结果

C++程序员不肖道:“你似乎太相信数据了,根本没有考虑道错误的输入”
Python程序员回答:“外面的try/except已帮我完成所有异常处理,不必担心越界崩溃而无法捕获”

Java程序员得意的看着自己百行代码:“我想知道你如何让你的同事来理解你的杰作?你有没有考虑过将
    类似gettoken之类的功能独立处理,让类似问题可以复用?我的代码说明了如何充分发挥Reflection和
    interface的优秀特性,在增加重用性的同时,提供清晰可读的代码”
Python无奈道:“这是‘纯粹的代码’,意思是不可修改,类似正则表达式,只要让人明白他的功能就行了,
    要修改就重写。再我能用三行代码完成以内绝不会有封装的想法,况且熟悉Python者也不觉得难读啊?”

C++程序员抛出杀手简:“如果让你一秒钟处理10w个ip转化的话怎么办?”
Python程序员觉得想睡觉:“你觉得我会蠢到还用Python做这样的事情么?”

此时C++程序员似乎并没听到,反而开始认真的思考起自己刚才提出问题来,一会只见他轻藐的看了另外两
人一眼,然后胸有成竹的转到电脑前,开始往屏幕上输入:“template <....”

小笑话:封装的陷阱,让人一边喊着“封装”或“复用”,一边在新项目中,全部打破重写,并解释为--重构
观点二:简单即是美,把一个东西设计复杂了,本身就是有问题的

思考题:上面的程序,如果反过来,将ip的整数形式转化为字符串,各位该如何设计呢??

例子2:输出一个对象各个成员的名称和值

g = lambda m: '\n'.join([ '%s=%s'%(k, repr(v)) for k, v in m.__dict__.iteritems() ])

用法:print g(x)
延伸:上面两个例子熟悉了lambda以后,建议可以尝试使用下 yield

观点总结

Q:“怎样才算做到注重What you think多于What you are writing”
A:“就是说你手上打着第1页需求的代码,眼睛却在看着第2页需求的内容,心里想着如何应对5-10页的东西”

国外多年前废除PASCAL改用Python做科研教学是有道理的,关于精简代码的例子举不胜举,用它编码时应
该有“一字千金”的感觉,否则最终写出来的,还是“伪装成Python的C++程序”。

编程本来就是快乐的,避免过多的体力劳动,赢得更多思考的时间。

思考题:到底是封装呢?还是放弃封装?
思考题:“more than one way to do it”是不是就是好事?它的反面是什么?

PS: 更多实用方法可以阅读 Daily Python URL 以及《Python Cookbook》

Skywind Inside:http://www.joynb.net/blog/






Friday, December 19, 2008

用python控制excel,请沈高手指点些比较简单的操作方法(**)


用python控制excel,请沈高手指点些比较简单的操作方法(**)

主要用了pyExcelerator模块,下载地址:http://sourceforge.net/projects/pyexcelerator


下面是代码,主要功能是将excel中读取的内容重新排版;


#!c:\python24\python.exe
#coding=cp936
from pyExcelerator import *
import tkFileDialog
class App2:
    def __init__(self,x,z,a):
        self.x=x
        self.z=z
        self.a=a
        self.sheets=sheets=parse_xls(self.a)  #读取excel文件并以字典的形式存储在sheets下
        self.w=w=Workbook()                   #新建一个excel文件
        self.ws=ws=w.add_sheet('firstexcel')  #excel文件内新建一个表
        self.cp1=cp1=[self.sheets[0][1][(5, 0)]] 
    def excel_py_v(self):
        self.ws.write(0, 5, self.sheets[0][1][(0, 0)])  #标题
        self.cp1=[self.sheets[0][1][(5, 0)]]
        self.ws.write(2, 1, self.cp1[0])  #产品
        self.ws.write(1,12,'max_input_all')
        self.ws.write(29,12,'cost_all')
        for self.x in range(500):
            self.x = self.x+1
            if self.sheets[0][1].has_key((int(5+self.x),0)):
                if self.sheets[0][1][(int(5+self.x),0)] == self.cp1[0]:
                    self.z=self.z+1
                    self.y = self.z
                for self.yy in range(int(self.y/2+1)):
                    self.ws.write(int(self.yy+3),0,self.sheets[0][1][(int(5+(2*self.yy)),1)]) # 时间
          
                if self.sheets[0][1][(int(5+self.x),0)] in self.cp1 and self.x > 0:
                    for self.yy in range(int(self.y/2+1)):
                        self.ws.write(int(self.yy+3),1,self.sheets[0][1][(int(5+(2*self.yy)),2)]) # 总呼入数量
               
                        self.ws.write(int(self.yy+3+28)-1,1,self.sheets[0][1][(int(5+(2*self.yy)),4)]) # 总应答数量
   
                if self.sheets[0][1][(int(5+self.x),0)] not in self.cp1:
                    self.cp1.append (self.sheets[0][1][(int(5+self.x),0)])
                    self.ws.write(2,len(self.cp1),self.cp1[-1])
                    for self.yy in range(int(self.y/2+1)):
                        self.ws.write(int(self.yy+3),len(self.cp1),self.sheets[0][1][(int(self.x+5+(2*self.yy)),2)]) # 总呼入数量
                       
self.ws.write(int(self.yy+3+28)-1,len(self.cp1),self.sheets[0][1][(int(self.x+5+(2*self.yy)),4)])
# 总应答数量                       
            else:
                break
        self.w.save('save_index.xls')


if __name__=='__main__':
    App2(0,0,tkFileDialog.askopenfilename()).excel_py_v()


感觉比较麻烦的是读取,用pyExcelerator读取excel的内容,将会以字典的形式存储,所以导入并排版的话较复杂...汗一个``  请沈高手指点些比较简单的操作方法```








开始Google App Engine之前应该做的事






开始Google App Engine之前应该做的事


六月 9th, 2008




然Google已经尽可能使GAE的安装和运行变得简单,但是自本博开始介绍GAE以来,还是不断有朋友反映入门教程中的例子无法运行。而有时候其实并不
是很复杂的问题,所以这一篇准备说一说,在开始Google App
Engine项目之前,我们应该预先做些什么准备工作。(本文以windows下的安装为例,因为我觉得既然是能搞得定unix或mac之类的用户,大概
也不需要看我在这里罗嗦了)



  1. Google App Engine目前只支持Python环境,所以你先要安装好你的Python运行环境。到Python官方网站下载window版本,(当前最新版本是2.5.2)这是一个标准的windows安装程序,按照提示安装就可以了。安装完后,进入命令提示行,敲入python,应该显示如下:
    Python 2.5.2 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on
    win32 Type "help", "copyright", "credits" or "license" for more information.
    >>>

  2. 如果python命令提示无效命令,那么有可能是系统无法找到相关文件,你可以将Python的安装路径加入到系统的path路径中。
  3. 请检查.py文件是否已经和python.exe关联起来了,如果没有,您可能需要重新启动一下机器
  4. 下载 Google App Engine SDK Windows installer 并安装
  5. 添加系统环境变量‘APP_ENGINE_HOME’ 设置它的值为GAE的安装路径 (通常安装路径为C:\AppEngine)
  6. %APPENGINE%\;%APPENGINE%\lib;%APPENGINE%\lib\yaml\lib;%APPENGINE%\lib\webob;加入到系统PATH变量或PYTHONPATH变量里面,以方便自己可以在任何地方运行GAE控制程序


windows平台下如何用Python杀进程






#from : http://www.joyloft.net/?p=1031
# "这段代码来自于一个很简单的场景:
#  在python中调一个程序。给这个程序设置一个timeout
#  假如一段时间程序还没有返回,就杀掉这个这个新开的进程。
#  本来以为我肯定不是第一个遇到这个问题的人,
#  但是网上搜了好久都没找到完整的办法,自己搞了一个。"

import ctypes
import sys

TH32CS_SNAPPROCESS = 0x00000002
class PROCESSENTRY32(ctypes.Structure):
     _fields_ = [("dwSize", ctypes.c_ulong),
                 ("cntUsage", ctypes.c_ulong),
                 ("th32ProcessID", ctypes.c_ulong),
                 ("th32DefaultHeapID", ctypes.c_ulong),
                 ("th32ModuleID", ctypes.c_ulong),
                 ("cntThreads", ctypes.c_ulong),
                 ("th32ParentProcessID", ctypes.c_ulong),
                 ("pcPriClassBase", ctypes.c_ulong),
                 ("dwFlags", ctypes.c_ulong),
                 ("szExeFile", ctypes.c_char * 260)]

def getProcList():
    CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot
    Process32First = ctypes.windll.kernel32.Process32First
    Process32Next = ctypes.windll.kernel32.Process32Next
    CloseHandle = ctypes.windll.kernel32.CloseHandle
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
    pe32 = PROCESSENTRY32()
    pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
    if Process32First(hProcessSnap,ctypes.byref(pe32)) == False:
        print >> sys.stderr, "Failed getting first process."
        return
    while True:
        yield pe32
        if Process32Next(hProcessSnap,ctypes.byref(pe32)) == False:
            break
    CloseHandle(hProcessSnap)

def getChildPid(pid):
    procList = getProcList()
    for proc in procList:
        if proc.th32ParentProcessID == pid:
            yield proc.th32ProcessID
    
def killPid(pid):
    childList = getChildPid(pid)
    for childPid in childList:
        killPid(childPid)
    handle = ctypes.windll.kernel32.OpenProcess(1, False, pid)
    ctypes.windll.kernel32.TerminateProcess(handle,0)


if __name__ =='__main__':
    args = sys.argv 
    if len(args) >1 :
        pid = int(args[1])
        killPid(pid)
    else:
        procList = getProcList()
        for proc in procList:
            print proc.szExeFile+'  '+str(proc.th32ParentProcessID) + '  '+str(proc.th32ProcessID)
    

#----------------------
#
# Usage demo
#
#----------------------
import subprocess
import time

#import winproc

timeout = 2
process = subprocess.Popen("cmd /k ping localhost -t",shell = True)
start = int(time.time())
while process.poll()==None:
    now = int(time.time())
    if int (now - start) >timeout:
        pid = process.pid
        break

winproc.killPid(pid)
        
print "End"

windows平台下如何用Python杀进程






#from : http://www.joyloft.net/?p=1031
# "这段代码来自于一个很简单的场景:
#  在python中调一个程序。给这个程序设置一个timeout
#  假如一段时间程序还没有返回,就杀掉这个这个新开的进程。
#  本来以为我肯定不是第一个遇到这个问题的人,
#  但是网上搜了好久都没找到完整的办法,自己搞了一个。"

import ctypes
import sys

TH32CS_SNAPPROCESS = 0x00000002
class PROCESSENTRY32(ctypes.Structure):
     _fields_ = [("dwSize", ctypes.c_ulong),
                 ("cntUsage", ctypes.c_ulong),
                 ("th32ProcessID", ctypes.c_ulong),
                 ("th32DefaultHeapID", ctypes.c_ulong),
                 ("th32ModuleID", ctypes.c_ulong),
                 ("cntThreads", ctypes.c_ulong),
                 ("th32ParentProcessID", ctypes.c_ulong),
                 ("pcPriClassBase", ctypes.c_ulong),
                 ("dwFlags", ctypes.c_ulong),
                 ("szExeFile", ctypes.c_char * 260)]

def getProcList():
    CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot
    Process32First = ctypes.windll.kernel32.Process32First
    Process32Next = ctypes.windll.kernel32.Process32Next
    CloseHandle = ctypes.windll.kernel32.CloseHandle
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
    pe32 = PROCESSENTRY32()
    pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
    if Process32First(hProcessSnap,ctypes.byref(pe32)) == False:
        print >> sys.stderr, "Failed getting first process."
        return
    while True:
        yield pe32
        if Process32Next(hProcessSnap,ctypes.byref(pe32)) == False:
            break
    CloseHandle(hProcessSnap)

def getChildPid(pid):
    procList = getProcList()
    for proc in procList:
        if proc.th32ParentProcessID == pid:
            yield proc.th32ProcessID
    
def killPid(pid):
    childList = getChildPid(pid)
    for childPid in childList:
        killPid(childPid)
    handle = ctypes.windll.kernel32.OpenProcess(1, False, pid)
    ctypes.windll.kernel32.TerminateProcess(handle,0)


if __name__ =='__main__':
    args = sys.argv 
    if len(args) >1 :
        pid = int(args[1])
        killPid(pid)
    else:
        procList = getProcList()
        for proc in procList:
            print proc.szExeFile+'  '+str(proc.th32ParentProcessID) + '  '+str(proc.th32ProcessID)
    

#----------------------
#
# Usage demo
#
#----------------------
import subprocess
import time

#import winproc

timeout = 2
process = subprocess.Popen("cmd /k ping localhost -t",shell = True)
start = int(time.time())
while process.poll()==None:
    now = int(time.time())
    if int (now - start) >timeout:
        pid = process.pid
        break

winproc.killPid(pid)
        
print "End"