python中的异常

python中的异常 异常是指程序中的例外,违例情况。异常机制是指程序出现错误后,程序的处理方法。当出现错误后,程序的执行流程发生改变,程序的控制权转移到异常处理。 Exception类是常用的异常类,该类包括StandardError,StopIteration, GeneratorExit, Warning等异常类。 StandardError类是python中的错误异常,如果程序上出现逻辑错误, 将引发该异常。StandardError类是所有内敛异常的基类,放置在默认的命名空间中,因此使用IOEroor, EOFError, ImportError等类,不需要导入exception模块。 StopIteration类判断循环是否执行到尾部,如果循环到尾部,则抛出该异常。 GeneratorExit类是由Generator函数引发的异常,当调用close()时引发该异常。 Warning类表示程序中的代码引起的警告。 python中的异常使用继承结构创建,可以在异常处理程序中捕获基类异常,也可以捕获各种子类异常,python中使用try...except语句捕获异常,异常子句定义在try子句后面。 try...except的使用方法 try...except用于处理问题语句,捕获可能出现的异常。try子句中的代码块放置可能出现异常的语句,except子句中的代码块处理异常。 演示try...except语句捕获IOError异常 try: file( hello.txt , r ) #如果文件不存在,引发异常 print 读文件 except IOError: #捕获IO异常 print 文件不存在 except: #其它异常 print 程序异常 python与Java的异常处理模式相似,异常处理语句也可以嵌套,演示如下: try: s = hello try: print s[0] + s[1] print s[0] - s[1] except TypeError: print 字符串不支持减法运算 except: print 异常 如果外层try子句中的代码引发异常,程序将直接跳转到外层try对应的except子句,而内部的try子句将不会被执行。 try...finally的使用方法 try...except后还可以添加一个finally子句。无论异常是否发生,finally子句都会被执行。所有的finally子句通常用于关闭因异常而不能释放的系统资源。 try: f = open( hello.txt , r ) try: print f.read(5) except: print 读文件异常 finally: print 释放资源 f.close() except IOError: print 文件不存在 使用raise抛出异常 当程序出现错误,python会自动引发异常,也可以通过raise显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行。 演示raise用法 try: s = None if s is None: print s 是空对象 raise NameError #如果引发NameError异常,后面的代码将不能执行 print len(s) except TypeError: print 空对象没有长度 自定义异常 python允许程序员自定义异常,用于描述python中没有涉及的异常情况,自定义异常必须继承Exception类,自定义异常按照命名规范以 Error 结尾,显示地告诉程序员这是 异常。自定义异常使用raise语句引发,而且只能通过人工方式触发。 from __future__ import division class DivisionException(Exception): def __init__(self, x, y): Exception.__init__ (self, x, y) #调用基类的__init__进行初始化 self.x = x self.y = y if __name__ == __main__ : try: x = 3 y = 2 if x % y 0: #如果大于0, 则不能被初始化,抛出异常 print x/y raise DivisionException(x, y) except DivisionException,div: #div 表示DivisionException的实例对象 print DivisionExcetion: x/y = %.2f % (div.x/div.y) assert语句的使用 assert语句用于检测某个条件表达式是否为真。assert语句又称为断言语句,即assert认为检测的表达式永远为真,if语句中的条件判断都可以使用assert语句检测。 ...

阅读全文 »

python常用的时间(time)的方法

我们先导入必须用到的一个module import time 设置一个时间的格式,下面会用到 ISOTIMEFORMAT= %Y-%m-%d %X 看一下当前的时间,和其他很多语言相似这是从epoch(1970 年 1 月 1 日 00:00:00)开始到当前的秒数。 time.time() 1180759620.859 上面的看不懂,换个格式来看看 time.localtime() (2007, 6, 2, 12, 47, 7, 5, 153, 0) localtime返回tuple格式的时间,有一个和它类似的函数叫gmtime(),2个函数的差别是时区,gmtime()返回的是0时区的值,localtime返回的是当前时区的值。 time.strftime( ISOTIMEFORMAT, time.localtime() ) 2007-06-02 12:54:29 用上我们的时间格式定义了,使用strftime对时间做一个转换,如果取现在的时间,time.localtime() 可以不用。 time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) ) 2007-06-02 12:54:31 time.strftime( ISOTIMEFORMAT, time.gmtime( time.time() ) ) 2007-06-02 04:55:02 上面展示了gmtime和localtime的区别。 查看时区用 time.timezone -28800 上面的值是一个秒值,是当前时区和0时区相差的描述,-28800=-8*3600,即为东八区。 帖几个简单的函数 def ISOString2Time( s ): convert a ISO format time to second from:2006-04-12 16:46:40 to:23123123 把一个时间转化为秒 return time.strptime( s, ISOTIMEFORMAT ) def Time2ISOString( s ): convert second to a ISO format time from: 23123123 to: 2006-04-12 16:46:40 把给定的秒转化为定义的格式 return time.strftime( ISOTIMEFORMAT, time.localtime( float( s ) ) ) def dateplustime( d, t ): d=2006-04-12 16:46:40 t=2小时 return 2006-04-12 18:46:40 计算一个日期相差多少秒的日期,time2sec是另外一个函数,可以处理,3天,13分钟,10小时等字符串,回头再来写这个,需要结合正则表达式。 return Time2ISOString( time.mktime( ISOString2Time( d ) )+time2sec( t ) ) def dateMinDate( d1, d2 ): minus to iso format date,return seconds 计算2个时间相差多少秒 d1=ISOString2Time( d1 ) d2=ISOString2Time( d2 ) return time.mktime( d1 )-time.mktime( d2 ) ...

阅读全文 »

Python 入门指南

注意: 目前已经用 Sphinx 重新整理一次,可以直接访问 http://www.pythondoc.com/pythontutorial3/index.html 或者 http://www.pythondoc.com/ The Python Tutorial Python 入门指南 Release: 3.1 Date: September 05, 2009 Python is an easy to learn, powerful programming language. It has efficient high-level data structures and a simple but effective approach to object-oriented programming. Python’s elegant syntax and dynamic typing, together with its interpreted nature, make it an ideal language for scripting and rapid application development in many areas on most platforms. Python是一门简单易学且功能强大的编程语言。 它拥有高效的高级数据结构,并且能够用简单而又高效的方式进行面向对象编程。 Python优雅的语法和动态类型,再结合它的解释性,使其在大多数平台的许多领域成为编写脚本或开发应用程序的理想语言。 The Python interpreter and the extensive standard library are freely available in source or binary form for all major platforms from the Python Web site, http://www.python.org/ , and may be freely distributed. The same site also contains distributions of and pointers to many free third party Python modules, programs and tools, and additional documentation. 你可以自由的从Python官方点,http://www.python.org,以源代码或二进制形式获取Python解释器及其标准扩展库,并可以自由的分发。 此站点同时也提供了大量的第三方Python模块、程序和工具,及其附加文档。 The Python interpreter is easily extended with new functions and data types implemented in C or C++ (or other languages callable from C). Python is also suitable as an extension language for customizable applications. 你可以很容易的使用C或C++(其他可以通过C调用的语言)为Python解释器扩展新函数和数据类型。 Python还可以被用作定制应用程式的一门扩展语言。 This tutorial introduces the reader informally to the basic concepts and features of the Python language and system. It helps to have a Python interpreter handy for hands-on experience, but all examples are self-contained, so the tutorial can be read off-line as well. 本手册非正式的向读者介绍了Python语言及其体系相关的基本知识与概念。 在学习实践中结合使用Python解释器是很有帮助的,不过所有的例子都是完整的,所以本手册亦可离线阅读。 For a description of standard objects and modules, see the Python Library Reference document. The Python Reference Manual gives a more formal definition of the language. To write extensions in C or C++, read Extending and Embedding the Python Interpreter and Python/C API Reference. There are also several books covering Python in depth. 如果需要了解相关标准库或对象的详细介绍,请查阅Python库参考文档。 Python参考手册提供了更多语言相关的正式说明。 如果想要使用C或C++编写扩展,请查阅Python解释器扩展和集成章节或Python/C API参考手册。 当然也可阅读一些深入介绍Python知识的图书。 This tutorial does not attempt to be comprehensive and cover every single feature, or even every commonly used feature. Instead, it introduces many of Python’s most noteworthy features, and will give you a good idea of the language’s flavor and style. After reading it, you will be able to read and write Python modules and programs, and you will be ready to learn more about the various Python library modules described in the Python Library Reference. 本手册不会尝试涵盖Python的全部知识和每个特性,甚至不会涵盖所有常用的特性。 相反的,它介绍了Python中许多最引人瞩目的特性,并且会给你一个关于语言特色和风格的认识。 读完之后,你将能够阅读和编写Python模块或程序,并为以后使用Python库参考手册继续学习诸多Python模块库做好准备。 The Glossary is also worth going through. 1. Whetting Your Appetite Appetitle 开胃菜 2. Using the ...

阅读全文 »

Twisted Web 代码示例

twisted.web.client getpage.py - 使用twisted.web.client.getPage 下载页面. dlpage.py -在下载页面过程中增加一个回调函数到twisted.web.client.downloadPage 用来显示错误信息 XML-RPC xmlrpc.py XML-RPC 服务器的几个方法 包括 echoing, faulting, returning deferreds 以及 failed deferreds xmlrpcclient.py - 使用 twisted.web.xmlrpc.Proxy来调用远程XML-RPC方法. advogato.py 使用twisted.web.xmlrpc添加日志到advogato.org,需要一个advogato.org帐号. 虚拟主机和代理 rootscript.py twisted.web.vhost.NameVirtualHost的例子 web.py 使用twisted.web.vhost.VHostMonsterResource作为反向代理处理某些特定文件. proxy.py -使用twisted.web.proxy把任何http请求通过代理端口转发到指定网站 hello.rpy.py - 使用twisted.web.static创建一个静态资源服务 fortune.rpy.py - 创建一个返回服务器运行进程输出的资源 l j.rpy.py - 使用twisted.web.microdom,twisted.web.domhelpers和回调链来提取显示一个LiveJournal用户的RSS页面. vhost.rpy.py - 创建一个twisted.web.vhost.VHostMonsterResource资源 report.rpy.py - 显示一个资源的各种属性,包括路径,主机和端口. users.rpy.py - 使用 twisted.web.distrib 发布一个 社区网站 的用户目录 simple.rtl 使用 twisted.web.resource.ResourceTemplate的模板示例 杂项 webguard.py -使用twisted.cred 来对twisted.web进行验证防止未授权的用户访问. silly-web.py - 使用wisted.web.distrib and twisted.spread.pb发布一个最基本的主从模型的分布式网站. google.py - 使用twisted.web.google获取我的手气不错的搜索页 soap.py 使用 twisted.web.soap 发布SOAP方法. 来源: http://twistedmatrix.com/documents/current/web/examples/#auto0 ...

阅读全文 »

Google 是如何做代码审查的

在上一篇文章中提到过,我已经不在Google工作了。我还没有想清楚应该去哪里 有两三个非常好的工作机会摆在我面前。因为在这段做决定时间里,我不再受雇于任何人,我想可以写一些专业性的东西,一些很有趣,但也会在同事和管理工作中导致关系紧张的东西。 Google是一个非常优秀的公司。他们做出了很多令人称赞的东西 既是公司外部,人们可以看到的东西,也是公司内部。有一些在公司内部并不属于保密的事情,在外部并没有给予足够广泛的讨论。这就是我今天要说的。 让Google的程序如此优秀的一个最重要的事情看起来是非常的简单:代码审查。并不是只有Google做这个事情 代码审查已经被广泛的认可为一种非常好的做法,很多人都在这样做。但我还没有看到第二家这样大的公司能把这种事情运用的如此普遍。在Google, 没有程序 ,任何产品、任何项目的程序代码,可以在没有经过有效的代码审查前提交到代码库里的。 所有人 都要经过代码审查。并且很正规的:这种事情应该成为任何重要的软件开发工作中一个基本制度。并不单指产品程序 所有东西。它不需要很多的工作,但它的效果是巨大的。 从代码审查里能得到什么? 很显然:在代码提交前,用第二群眼睛检查一遍,防止bug混入。这是对其最常见的理解,是对代码审查的好处的最广泛的认识。但是,依我的经验来看,这反倒是它 最不重要 的一点。人们确实在代码审查中找到了bug。可是,这些在代码审查中能发现的绝大部分bug,很显然,都是微不足道的bug,程序的作者花几分钟的时间就能发现它们。真正需要花时间去发现的bug不是在代码审查里能找到的。 代码审查的最大的功用是纯社会性的。如果你在编程,而且 知道 将会有同事检查你的代码,你编程态度就完全不一样了。你写出的代码将更加整洁,有更好的注释,更好的程序结构 因为你 知道 ,那个你很在意的人将会查看你的程序。没有代码审查,你知道人们最终还是会看你的程序。但这种事情不是立即发生的事,它不会给你带来同等的紧迫感,它不会给你相同的个人评判的那种感受。 还有一个非常重要的好处。代码审查能 传播知识 。在很多的开发团队里,经常每一个人负责一个核心模块,每个人都只关注他自己的那个模块。除非是同事的模块影响了自己的程序,他们从不相互交流。这种情况的后果是,每个模块只有一个人熟悉里面的代码。如果这个人休假或 但愿不是 辞职了,其他人则束手无策。通过代码审查,至少会有两个人熟悉这些程序 作者,以及审查者。审查者并不能像程序的作者一样对程序十分了解 但他会熟悉程序的设计和架构,这是极其重要的。 当然,没有什么事情能简单的做下来的。依我的经验,在你能正确的进行代码审查前,你需要花时间锻炼学习。我发现人们在代码审查时经常会犯一些错误,导致不少麻烦 尤其在一些缺乏经验的审查者中经常的出现,他们给了人们一个很遭的代码审查的体验,成为了人们接受代码审查制度的一个障碍。 最重要的一个原则:代码审查用意是在代码提交前找到其中的问题 你要发现是它的 正确 。在代码审查中最常犯的错误 几乎每个新手都会犯的错误 是,审查者根据自己的编程习惯来评判别人的代码。 对于一个问题,通常我们能找出十几种方法去解决。对于一种解决方案,我们能有百万种编码方案来实现它。作为一个审查者,你的任务不是来确保被审查的代码都采用的是你的编码风格 因为它不可能跟你写的一样。作为一段代码的审查者的任务是确保由作者自己写出的代码是正确的。一旦这个原则被打破,你最终将会倍感折磨,深受挫折 这可不是我们想要的结果。 问题在于,这种错误是如此的普遍而易犯。如果你是个程序员,当你遇到一个问题,你能想到一种解决方案 你就把你想到的方案作为标准答案。但事情不是这样的 作为一个好的审查者,你需要明白这个道理。 代码审查的第二个易犯的毛病是,人们觉得有压力,感觉非要说点什么才好。你知道作者用了大量的时间和精力来实现这些程序 不该说点什么吗? 不,你不需要。 只说一句 哇,不错呀 ,任何时候都不会不合适。如果你总是力图找出一点什么东西来批评,你这样做的结果只会损害自己的威望。当你不厌其烦的找出一些东西来,只是为了说些什么,被审查人就会知道,你说这些话只是为了填补寂静。你的评论将不再被人重视。 第三是速度。你不能匆匆忙忙的进行一次代码审查 但你也要能迅速的完成。你的同伴在等你。如果你和你的同事并不想花太多时间进行代码复查,你们很快的完成,那被审查者会觉得很沮丧,这种代码审查带来的只有失望的感觉。就好象是打搅了大家,使大家放下手头的工作来进行审查。事情不该是这样。你并不需要推掉手头上的任何事情来做代码审查。但如果中途耽误了几个小时,你中间还要休息一会,喝杯茶,冲个澡,或谈会儿闲话。当你回到审查现场,你可以继续下去,把事情做完。如果你真是这样,我想没有愿意在那干等着你。 ...

阅读全文 »

python challenge 33解题总结

网页注释中提示: !--If you are blinded by the light, remove its power, with its might. Then from the ashes, fair and square, another truth at you will glare.-- python challenge 33网址: www.pythonchallenge.com/pc/rock/beer.html 注意到图像名称是beer1.jpg,看看 http://www.pythonchallenge.com/pc/rock/beer2.jpg 图上提示 no, png,看看 http://www.pythonchallenge.com/pc/rock/beer2.png 好像是个有个x的灰度杂波图 查看图片信息(通过img.getcolors()) 可知,图像有66种颜色: [(1532, 1), (232, 2), (963, 7), (189, 8), (724, 13), (329, 14), (549, 19), (243, 20), (144, 25), (424, 26), (119, 31), (328, 32), (126, 37), (339, 38), (126, 43), (357, 44), (107, 49), (225, 50), (79, 55), (609, 56), (181, 61), (356, 62), (70, 67), (298, 68), (23, 73), (164, 74), (26, 79), (354, 80), (47, 85), (341, 86), (139, 91), (257, 92), (104, 97), (505, 98), (192, 103), (224, 104), (114, 109), (310, 110), (32, 115), (183, 116), (238, 121), (198, 122), (117, 127), (327, 128), (110, 133), (342, 134), (118, 139), (342, 140), (145, 145), (323, 146), (152, 151), (324, 152), (161, 157), (323, 158), (175, 163), (317, 164), (183, 169), (317, 170), (171, 175), (337, 176), (198, 181), (318, 182), (241, 187), (283, 188), (1348, 193), (272, 194) 仔细看发现,每两种颜色值相邻,可以分为一组(1和2, 7和8, 13和14 ...), 每组颜色的像素数累加后开平方可得一个整数,比如颜色1和2的像素数 sqrt(1532+232)=42, 颜色1,2,7和8的像素数 sqrt(1532+232+963+189)=54 颜色1,2,7,8,13和14的像素数 sqrt(1532+232+963+189+724+329)=63 再根据提示中的 light , remove its power 和 square 猜想: 0) 以所有像素为整体开始; 1) 以当前像素数开平方的值做为宽高建立新图片; 2) 将当前像素中颜色值最大的一组像素标为最暗其他则标为最亮(反过来也行),然后输出到新图片中; 3) 从当前像素中去掉当前颜色值最大的一组(因为最亮嘛),然后转到第1)步; 如此循环共建立33个新图片,查看一下输出是否有意义 源代码如下: amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / def level_33(): amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / img=Image.open(r amp;amp;amp;amp;#39;d:beer2.png amp;amp;amp;amp;#39;) amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / colors=img.getcolors() amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / cl=len(colors) amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / l=img.getdata() # 当前操作的像素集合 amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / ## starttime=clock() amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / amp;amp;amp;lt;/p amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / amp;amp;amp;lt;p amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / i=cl-1 # 65 amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / while i amp;amp;amp;amp;gt;0: amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / amp;gt; lt;br / gt; br / dim=sqrt(len(l)) # 确定宽高 amp;amp;amp;lt;br / amp;amp;amp;gt; amp;amp;lt;br / amp;amp;gt; amp;lt;br / am ...

阅读全文 »

趣味编程网站Codecademy新增了Python编程语言的学习课程

趣味编程网站Codecademy今天增加了Python编程语言的编程学习课程。就在上个月,公司刚获得一轮1000万美元的融资,Codecademy网站也新增5个语言的版本,包括中文、俄语、日语、西班牙语和德语。 Codecademy此前就已经支持JavaScript、HTML和CSS三种编程语言的编程学习课程。公司联合创始人Zach Sim表示,支持Python编程语言只是一个开始,Codecademy在未来还将提供更多的编程语言学习课程。不过Sims并没有透露具体还将新增哪些编程语言。 去年年底,Codecademy推出了实验室Labs功能,目的是为了能让人们更方便地学以致用,免去下载安装桌面版本的编辑器或集成开发环境(IDE)的麻烦。除了编辑,Codecademy Labs还能让你运行和下载可执行文件,拿到别的地方去运行。你不仅可以在上面学习磨练你的JavaScript,要是你在别的地方也学了Python和Ruby,你同样可以在Codecademy上面磨刀霍霍地训练起来。不过当时还没有Python课程,今天Codecademy上的Python课程终于推出。 Sims还表示,从一开始,Codecademy用户就对Python编程课程有强烈的需求,其中大部分是中学或大学的老师。对于想学习编程的新手,他们不妨加入Codecademy推出的新年编程项目Code Year,他们在这里可以进行JavaScript、HTML、CSS和jQuery的混合编程练习。

阅读全文 »

谈谈Python函数的默认参数

Python中很奇葩的一个地方是它的函数的默认参数的值,仅仅在def语句执行的时候计算一次。这会导致什么问题呢? 奇葩的例子 我们来看一个例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 In [44]: def packitem(item, pkg = []): ....: pkg.append(item) ....: return pkg In [45]: l = [100,200] In [46]: packitem(300, l) Out[46]: [100, 200, 300] In [47]: packitem(1) Out[47]: [1] In [48]: packitem(2) Out[48]: [1, 2] In [49]: packitem(3) Out[49]: [1, 2, 3] 这个可以看到packitem的默认参数pkg=[]仅仅计算了一次。而之后的packitem函数调用时,pkg都指向了最初创建的那个列表。 为什么 为什么会这样呢? 我们此时需要从Python编译出来的字节码中寻求答案。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 In [65]: def main(): ....: def packitem(item, pkg = []): ....: pkg.append(item) ....: return pkg ....: print packitem(1) ....: print packitem(2) ....: print packitem(3) In [66]: main() [1] [1, 2] [1, 2, 3] In [67]: dis.dis(main) 2 0 BUILD_LIST 0 3 LOAD_CONST 1 (code object) 6 MAKE_FUNCTION 1 9 STORE_FAST 0 (packitem) 5 12 LOAD_FAST 0 (packitem) 15 LOAD_CONST 2 (1) 18 CALL_FUNCTION 1 21 PRINT_ITEM 22 PRINT_NEWLINE 6 23 LOAD_FAST 0 (packitem) 26 LOAD_CONST 3 (2) 29 CALL_FUNCTION 1 32 PRINT_ITEM 33 PRINT_NEWLINE 7 34 LOAD_FAST 0 (packitem) 37 LOAD_CONST 4 (3) 40 CALL_FUNCTION 1 43 PRINT_ITEM 44 PRINT_NEWLINE 45 LOAD_CONST 0 (None) 48 RETURN_VALUE 可以看出。packitem函数的默认参数pkg的值是在第一条字节码创建的。随后在MAKE_FUNCTION指令的时候一起和code object打包成一个函数对象,然后通过STORE_FAST 0存在了FAST表的第0位。 后续的函数调用通过LOAD_FAST 0指令将packitem的函数对象取出,然后通过CALL_FUNCTION调用(对于CALL_FUNCTION,我们会在后续的文章进行探讨)。整个函数调用的过程并没有涉及到默认参数值的初始化。 所以,可见,Python函数的默认参数的值仅在函数定义的时候计算,后续的函数调用时的默认参数都是引用最初创建的那个对象。 Hack It 既然Python没有在我们进行函数调用的时候帮我们重新创建的默认参数的值,那我们就自己动手,丰衣足食。 第一种方案是是用不可变的默认值,例如None,然后在函数内部进行判断。此法略显麻烦。 第二种方案是通过装饰器来解决这个问题。 这段脚本是Sean Ross写的,非常感谢他。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 In [74]: def freshdefaults(f): ....: fdefaults = f.func_defaults ....: def refresher(*args, **kwds): ....: f.func_defaults = copy.deepcopy(fdefaults) ....: return f(*args, **kwds) ....: return refresher In [75]: @freshdefaults ....: def packitem(item, pkg = []): ....: pkg.append(item) ....: return pkg In [76]: l = [100,200] In [77]: packitem(300, l) Out[77]: [100, 200, 300] In [78]: packitem(1) Out[78]: [1] In [79]: packitem(2) Out[79]: [2] In [80]: packitem(3) Out[80]: [3] 可以看到,packitem的输出符合我们的预期了。我们通过装饰器freshdefault,完成了对于默认参数的更新。packitem的pkg已经在每次调用的时候更新了。 装饰器等价于 1 myfunc = wrapper(myfunc) 在此例子中 ,等价于在后面加上了一句 1 packitem = freshdefault(packitem) 参考 Python Cookbook Python源码剖析 ...

阅读全文 »

用 Unix 的设计思想来应对多变的需求

现实当中的例子

让我先举几个现实生活中的例子: 1、现实社会中,制造灯具的工厂完全不关心制造灯泡的工厂,制造灯泡的工厂完全不关心制造灯具的工厂,但是,灯泡和灯饰可以很完美地组合成用户所喜欢的样子(这和@weidagang 在“需求变更和IoC”说到的那个PC的例子相仿)。他们是怎么做到的? 2、互联网上,做网站的人完全不用关心用户在用什么样的操作系统,什么样的客户端浏览器(当然事实上,浏览器的不标准让网站那边很头痛,这里只是举个例),反过来,上网的人也不关心做网站的人在用什么的技术开发网站。但是大家在完全不关心对方的情况下,可以很正常地协同工作在一起。为什么? 这样的例子太多了。为什么可以做成这样呢?因为大家依赖的是一个接口,灯具和灯泡并不互相依赖,他们依赖的是一个接口,做网站的人和浏览网站的人依赖的还是接口——HTTP协议。这就是面向对象的核心思想——依赖于接口而不是实现,这就是解耦。当你看过这两个例子以后,我希望你以后设计的软件至少不能比我们现实社会中的这些方法要差。不然,你就是在让社会倒退了,呵呵。 你会说,这和Unix,和应对需求变化有什么关系?好让我们再来看一下Unix的设计。

Unix设计的例子

下面是几个Unix下的例子: 1、Unix下,所有的硬件都可以通过文件的方式存取。其统统在/dev下。于是,软件和硬件的耦合被解开了,操作系统只需要把硬件统统变成文件,而程序只需要使用三个东西,一个是fd,一个是read(),一个是write(),就可以来操作任意的硬件了,这就是抽象,简单到不行。 2、Unix下,所有的命令都可以用管道串起来(管道绝对是个伟大的发明),这样,所有的命令间的交互全部解耦到只依赖于STD_IN, STD_OUT设备上。最酷的是,用户可以使用管道任意地拼装那些命令,以完成各式各样的功能。管道这个设计思想可以映射为今天的Web Service,你可以任意地拼装各种Web Service。 看到这里,你会发现,这还是解耦,本质上来说,也是一种依赖倒置——OOD的精髓。但是,Unix还不仅仅是这些。我们再来看几个例子: 1、Unix下,软件都是绿色地安装。在iOS上更明显——各个程序间基本上互不干扰,这个程序产生的垃圾文件不会影响到另一个程序。你删掉一个程序不会让另一个程序不举,各是各的空间。你可以删除这些程序,只要把内核心留着,系统照样可以启动。 2、Unix下,你可以通过设置一些环境变量,让多种环境同时存在,比如:某个LAMP用的是Apache 2.0, Mysql 4.0, PHP 4.0,某个LAMP用的是Apache 2.2, Mysql 5.0,PHP5.3,你不但可以方便地在系统中切换这两个环境,你甚至还可以同时启动他们。 3、Unix下,你可以随意地替换你想要的程序。比如,你不喜欢bash,你可以替换成ksh/csh等,你不喜欢awk ,你可以替换成 gawk ,所有的东西都像零件一样,你不喜欢什么,你就可以替换什么。 这三个例子告诉了我们——当你把你的软件设计地耦合度非常地低时,你可以随意地组合,随意地安排你的系统。相当的灵活,灵活到Windows到今天都学不会。

应对需求变化

看到这里,你可能明白我想说的是什么了,你可能开始觉得怎么样的系统设计会更有效了。如果你还记得《Steve Y 对平台的长篇大论》,你就会知道我想说什么了。是的,我想说的就是,当你真正了解了Unix的设计思想后,你会觉得今天的很多东西都是对Unix设计思想的一种传承或是变种。这种东西就是: 1)解耦,解耦,解耦。尽量地让你的模块不要在实现上耦合,而是耦合某个规范,某个标准。 2)KISS,KISS,KISS。要做到高度解耦,你的模块就一定要很简单,当然不是说简单到只有几行代码,而是简单到只干一件事,并把这件事干到极致。然后通过某个标准拼装起来。 3)拼装,拼装,拼装。我想不起来是谁说的了,这句话是这样的,当我想用一个模块的时候,我直接调用就好了,没有必要像C或Java一样,还要编译。是的,拼装需要一个框架,需要一种标准协议,然后让所有的系统都耦合在这种规范上,各自独立运行,就像一个机器上的各个部件一样,当我觉得这个部件不爽,换了就是了。(例如,当我们在尝试不同的算法的时候) 想想建材和家俱市场,无论用户过来想装修什么,我都可以满足用户的不同需求,只要你是和家装相关,我基本上都能满足你,不是吗?无论你怎么变,只要不变态,我基本上都可以满足你。这就是解耦,拼装带来的好处。 你可能会说我说得太简单了,另一方面,你可能觉得有一些系统这样做没必要,我承认,不过,你可以有选择的或多或少地试试。(其实,我相信你已经在不自觉得或多或少地使用这种方式开发软件了)

阅读全文 »

在 web.py 中使用装饰器

import web
urls = (
'/', 'hello',
)
app = web.application(urls, globals())
def hold(func):
print 'run hlod'
def f(self):
print 'in hold func'
return 'hold'
return f
class hello:
@hold
def GET(self):
print 'in hello'
return 'hello'<



 

 

现在的问题是,hold会在什么时候调用?

过去我一直以为是每次调用GET函数的时候会调用一遍hold函数
但事实并不是这样的,
事实是,当定义GET函数加载的时候,就会调用一遍hold函数
而且仅仅调用一遍hold,
这时候hold返回的函数就会替代原始的GET函数定义,
所以运行这点python代码,输出结果如下

 

 

 

http://0.0.0.0:8080/
run hlod
in hold func
10.0.2.2:51602 - - [23/Sep/2011 08:04:11] "HTTP/1.1 GET /" - 200 OK
10.0.2.2:51602 - - [23/Sep/2011 08:04:11] "HTTP/1.1 GET /favicon.ico" - 404 Not Found
in hold func
10.0.2.2:51602 - - [23/Sep/2011 08:04:12] "HTTP/1.1 GET /" - 200 OK 
				
				
				

阅读全文 »