PyCon 大会相关资料(视频+PPT)

会议PPT下载: http://cn.pycon.org/2011/schedule 洪强宁-豆瓣的Python应用和创新 http://www.tudou.com/programs/view/fvnGyGXTvLM/ Daniem-Scale web application stack with coro-thread http://www.tudou.com/programs/view/afNO_Yq1kLc/ 沈葳–Python通向未来之路 http://www.tudou.com/programs/view/Dx8LHWMvjps/ 潘俊勇-易度PaaS云开发平台技术内幕 http://www.tudou.com/programs/view/9BfMlTho_1A/ 土豆网黄冬-系统工程师的非专业课 计费与流量管理 http://www.tudou.com/programs/view/kGcDov8GxNM/ 陈正—Introduction_to_SAE_Python http://www.tudou.com/programs/view/iMP1dKMgJYc/ Ryan Ye-Schemaless-data-model-Pycon http://www.tudou.com/programs/view/M8Ku2upwdGg/ 首届中国Python2011大会Q A(1) http://www.tudou.com/programs/view/PXVBJY82JrM/ 李迎辉- Web框架开发思考与实践 http://www.tudou.com/programs/view/7ua4wTEQAac/ 首届中国Python2011大会Q A(2) http://www.tudou.com/programs/view/cWEM79vOYVg/ 赖勇浩-Python 之于 webgame 的应用 http://www.tudou.com/programs/view/PP4K6ZD2r-g/ 王剑锋-OpenERP二次开发 http://www.tudou.com/programs/view/f90a0p3-sQc/ 李俊东-与python一路走来 http://www.tudou.com/programs/view/DAmnmtfwHgQ/ 林君-用tornado搭建实时应用 http://www.tudou.com/programs/view/ATbooIAjpO0/ 王浩飞-openstack_pycon http://www.tudou.com/programs/view/Za52sDDCp-g/ 宋进亮-工程师职业规划探讨 http://www.tudou.com/programs/view/BomiVOnBBe4/ Steven Yang- Workend, where developer meets designer http://www.tudou.com/programs/view/0_VW4SENilQ/ 钟子飞-图形化大规模网络设备 http://www.tudou.com/programs/view/hJD2iyruUqY/ ...

阅读全文 »

Pysvn使用手记--安装篇

PySVN提供了Python语言环境下进行Subversion操作的语言支持,比官方的python语言绑定有更好的API。项目包括了pysvn 和WorkBench ,这两个简单的区分是workbench是带有GUI的功能更加强大的工具。pysvn的目的就是为了方便我们这些pythoner,能够使用python去操作subversion。由于对workbench的需求不是很大,所以这里主要介绍pysvn Extension。 目前pysvn Extension的版本号是1.7.5,能够在windows,unix/linux,mac os上,windows和MAC OS上提供了安装包,在unix/linux上可以使用: Ubuntu sudo apt-get install python-svn sudo apt-get install svn-workbench Fedora packages pysvn yum install pysvn 另外就是可以选择编译源码安装。windows和unix/linux(mac os)上都可以选择自己编译源码的方式,这里可以参考提供的安装文档的方式进行: Prerequisites To build pysvn you will require: Python 2.2 or later with these options: Python runtime package Python development package Python pyexpat package subversion 1.5.x or 1.6.x with these options: Subversion client package Subversion development package PyCXX V6.2.2 to build against Python 2 or Python 3 which is included in the pysvn source kit. Some distributions will split python and subversion into more the one package. You will need to find all the packages that give you the options listed above. Building on win32 These instructions assume you have Microsoft Visual C++ 6.0 to compile the code and INNO 4.0.10 to create the installation kit. Note: You must build with MSVC 6.0 as python 2.3 and earlier was built with that version. Note: You must build with MSVC 2003.NET for python 2.4 or Python 2.5. Note: You must build with MSVC 2008 (9.0) for Python 2.6 or later and python 3.0 or later. Build subversion (tested with SVN 1.5.6 and svn 1.6.15) Fetch and expand the pysvn source code into extdir Expand pycxx-6.2.1.tar.gz into extdir \Import if not using a source kit Edit Builder\builder_custom_init.cmd to match the locations of the sources. cd Builder builder_custom_init.cmd nmake -f win32.mak build To install the built kit Uninstall any previous kit (control panel's Add/Remove programs) nmake -f win32.mak install Building on unix and Mac OS X systems. Install subversion. When installing from packages you will need to install the devel packages as well. For example on Fedora/Redhat subversion-devel, apr-devel, apr-util-devel and their dependancies. Get the pysvn source code For Python 2 or Python 3 builds: tar xzf pycxx-6.2.1.tar.gz into extdir /Import if not using a source kit cd Source For Python 2 builds: backport the PySVN code using python setup.py backport Create the Makefile using python setup.py configure make cd Tests Test pysvn by running make Install pysvn by copying the following from Extension/Source to python site-specific directory. mkdir python-libdir /site-packages/pysvn cp pysvn/__init__.py python-libdir /site-packages/pysvn cp pysvn/_pysvn*.so python-libdir /site-packages/pysvn 问题: centos上的python以及subversion的版本太老,这样会造成编译pysvn的问题,经常会出现某些动态文件以及.h文件不存在的信息。 ...

阅读全文 »

抓取应届生的职位信息的代码

抓取应届生的职位信息的代码如下:(前五页) #!/usr/bin/env python __author__ = "Dan Deng (sixu05202004@gmail.com)" __version__ = "0.1.0" __copyright__ = "Copyright (c) 2011-2012 Dan" __license__ = "New-style BSD" from BeautifulSoup import BeautifulSoup import re , urllib2 , pickle pattern = re . compile ( '/job-001.*' ) num = 0 test ={} for i in range ( 1 , 6 ): url = 'http://www.yingjiesheng.com/beijing-morebbsjob-' + str ( i )+ '.html' pagesource = urllib2 . urlopen ( url ) soup = BeautifulSoup ( pagesource ) result = soup . findAll ( 'a' , href = pattern ) for j in range ( 0 , len ( result )): test [ str ( result [ j ][ 'href' ])]= str ( result [ j ]. string ) soup . clear () f = open ( 'D:temp1.plk' , 'rb' ) test2 = pickle . load ( f ) f . close () for eachline in test . iterkeys (): if eachline not in test2 . iterkeys (): print 'http://www.yingjiesheng.com' + eachline , test [ eachline ]. decode ( 'utf-8' ). encode ( 'utf-8' ) num += 1 print "the count of update jobs is %d" % num if num : f = open ( 'D:temp1.plk' , 'wb' ) pickle . dump ( test , f ,- 1 ) f . close () # for eachinle in result: # if eachline not in joblist: # joblist.append() 7.31号的结果类似如下: http://www.yingjiesheng.com/job-001-117-934.html [北京]北京人民艺术剧院2011招聘应届大学毕业生 http://www.yingjiesheng.com/job-001-118-753.html [北京]IBM GPS诚聘BAO Solution Developer|Lead http://www.yingjiesheng.com/job-001-118-341.html [北京]北京北阳电子招聘图形视频方向软件工程师 http://www.yingjiesheng.com/job-001-118-788.html [北京]互联网公司急聘J2EE后台开发高级工程师|市场营销 http://www.yingjiesheng.com/job-001-118-356.html [北京]北京成府工业新科技研究院2011招聘 http://www.yingjiesheng.com/job-001-117-822.html [北京]招聘Web前台开发工程师 http://www.yingjiesheng.com/job-001-118-767.html [北京]某保险公司总部招聘数据分析人员 。。。。。。 ...

阅读全文 »

不使用+,实现加的操作

  1. #! /usr/bin/env python
  2. # coding: utf-8
  3.  
  4. def newadd(x,y):
  5.     if not y:
  6.         return x
  7.     sum1=x^y
  8.     temp=(x>y)<<1
  9.     return newadd(sum1,temp)
  10.  
  11.  
  12.  
  13. if __name__=='__main__':
  14.     a=int(raw_input("please inter the first number:"))
  15.     b=int(raw_input("please inter the second number:"))
  16.     print newadd(a,b)

整体思路是通过位的运算来实现。

阅读全文 »

《测试驱动开发》读后感

这本书的作者是“极限编程”之父Kent Beck,书写得很薄,每一章都只有几页的长度。这就好像用TDD方法写出的代码般,每一个单元都是精巧明快的,使得人们很容易读懂,也使人们更有意愿将其读懂(短的文章更能激发人们的阅读欲望,不是吗?)。加之作者的笔调也十分轻松,这种小薄册要比那些百科全书式的大部头读起来舒服许多。 第一部分讲了一个支付系统中支持多币种需求的例子。作者以很慢的节奏来讲解TDD的过程,这节奏慢到甚至让我有一点难以接受,然而当着个例子最终完成的时候,回头看看整个开发过程,感觉如作者所述,不觉间竟然已经走出了这么长的一段距离。个人感觉,假如以传统的先设计再编码的方式开发,除非是非常非常有经验的程序员,否则很容易会得到不符合需求的设计或者花过多精力在需求之外的设计上编码。 第二部分是一个十分特别的例子。一种“提靴带”的开发方式:用xUnit测试框架来测试驱动开发xUnit本身。似乎这种模式只在编译器的开发中存在。从无到有,神奇之至。就好像xUnit被作者注入了神奇的DNA,然后使命般地自我演化生长出一个优秀的单元测试框架。我这么说可能有些夸张了。我并不认为实际的开发工作中会有这么美妙的设计过程。作者作为JUnit的开发者之一,对这套框架自然是了然于胸,设计起来也一定会有举重若轻之感。虽然我没学过Python,但也能跟着作者的“YY思路”一同前行。 第三部分作者揭示了测试驱动开发的模式。这部分有些稍有些“政治课本”的味道了,但依然不失风趣。有了前面两个例子,的铺垫,理解起来也相对容易些了。其中包含了TDD的实践原则(不可运行、可运行、重构)和TDD指导编码的技巧(“设计模式”和“重构”两章)。当读者有了更多的实践和经验,重读这部分会得到更多的体会。 TDD之所以有效率,是因为它使程序员的注意力完全集中于现有的需求,不必过多考虑变化。凡是参加过英语考试的人几乎都知道这样一个应试技巧:做阅读理解题的时候,先看问题然后去原文找答按要比通读全文再看问题做答能更快更准确地答完。这是因为看问题找答案使考生将精力集中到“现有的考试需求”上,回头阅读原文的时候自然而然地忽略掉与问题无关的词句,迅速找到问题相关的段落,提炼出答案。这就是测试驱动开发。我们只需要为现有的需求编写对应的测试用例,然后努力使这些用例通过测试。 TDD有效率的另一方面就是自动化单元测试。这是程序员给代码上的保险。作者在书中打了个比喻,TDD就像是井绳上的防滑扣,它在你没有了力气或者不慎手滑时不会使得吊桶跌落井底。想象一个没有使用TDD方法的项目,由于设计并没有基于项目自身的需求实践,而是基于设计者的经验和推断,在编码阶段,开发人员就会经常一步三回头地回顾设计,并且针对实际编码中遇到的问题做出一些修改;在集成测试阶段以及最终发布之后,没有单元测试用例,在发现Bug时,找出Bug的成因就成了一个艰难的任务。单元测试是从需求的实际出发,通过一点一点实践向前推进的,在编码的同时,也就将部分Bug限定了活动范围;而且单元测试迫使程序员写出便于测试的代码,便于测试的代码,就是的低耦合的代码,一块一块短小清晰的代码要比一坨一坨冗长纠结的代码更容易阅读;自动化测试使测试的成本降低,程序员的每次推进都有会得到快速的检验,前期花在自动化上的工作是值得的,“一次投保,终身收益”;在发现Bug或者遇到需求变更时,程序员也能很快定位问题,因为测试用例给了程序员解决问题的线索,更给了程序员拥抱变化的勇气。 测试驱动开发,是一种很人性化的开发方法。其中包含了很多心理学因素。它给了程序员勇气。即使不是基本功扎实程序员,也能用这种方法开发出好的程序(看一下书中附录B那个用TDD方法开发的Fibonacci数列程序,是不是觉得有些好笑?但回顾你第一次写Fib时的情景,是不是有似曾相识的感觉?);它使程序员能把问题管理好,使得代码是新鲜的、干净的、可控的;测试用例也量化了项目开发的进度,项目如期交付变得可能。 一直以来,我都有这样一个愿景:程序员们不再需要加班,不用再每天盯着显示器焦头烂额,不再有产品交付前的Debug炼狱,不再时常被发布版Bug噩梦惊醒,每晚睡得踏实, 每天8小时上班,我们可以一边喝着香醇的咖啡茶一边远望窗外的美丽风景,当自动测试报告出来后,我们能对着它微笑,然后轻松处理其中的每一个问题。我不敢说TDD能够实现这个愿景,但至少它给了我实现这愿景的希望。 Keep the bar green, to keep the code clean!

阅读全文 »

python 菜谱(python cookbook) 1.3 测试一个对象是否是字符串

任务:测试一个对象是否是字符串

对于这个问题,很多人会考虑使用type来解决:type(obj) is type('')。

但是问题是type('')得到的返回是<type'str'>,而在python里面字符串是包括string和unicode(其实还有userstring,不过目前不推荐使用,这个可以称为类string对象),显然unicode对象无法通过这个解决方案。

内置函数instance和basestring就能很好的解决这个问题(不过对于userstring也是无能为力):

def isString(anbj): return isinstance(anbj,basestring)

实际上上面的方案能使用绝大部分场景(对于UserString),但是严格意义上来说,我们只是从所谓的“属性”来检查是否属于字符串对象,还需要从“行为”上来对对象进行检验。比如通过一些字符串操作。

阅读全文 »

What is Pythonic?(Pythonic是什么东东?)

What is Pythonic? 作者:Martijn Faassen 原文地址: http://faassen.n--tree.net/blog/view/weblog/2005/08/06/0 “Pythonic”到底是什么意思?这个问题几个月前出现在EuroPython 邮件列表,EuroPython 邮件列表主要是用来计划EuroPython 会议的邮件列表。这是个很有意思的问题,我看到这个词被到处使用,但是很少有人能够尝试给出解释。随后,许多人这也包括我对“Pythonic”这个词给出自己的解释。我修饰了一下答案,并把它放在博客上,希望它对您们有用。 “Pythonic” 是一个很模糊的概念,尽管还没有“智能”或“生命”那么模糊。当你试着给出它们定义的时候,发现会无从下手。尽管它难以定义,并不意味着它们没用,事实上人们极善于处理混乱的定义。“Pythonic” 有点像“Python惯用法”的意思,现在我们需要进一步阐述“Pythonic”的蕴含。 随着时间的推移,Python持续地改进以及社区不断地成长,许多关于如何正确地和有效地使用 Python 的奇思妙想就顺应而出。一方面 Python 鼓励使用大量的惯用法来完成许多地任务(“完成任务的唯一方法”);另一方面,社区不断演变的新的惯用法的又反过来影响了语言的进化,以更好地支持惯用法。比如新进入的字典的 .get() 方法,它把 has_key() 和元素存取两个操作组合为一个操作,从中可以看出这种进化。 惯用法往往不能直接从其它编程语言移植过来。如下文是实现对一个序列里的每个元素执行一个操作的 C 语言实现: for (i=0; i mylist_length; i++) { do_something(mylist[i]); } 直接的等效 Python 代码是这样的: i = 0 while i mylist_length: do_something(mylist[i]) i += 1 这段代码能够完成工作,但并不 Pythonic,它并不是 Python 语言推荐的惯用法。让我们来改进一下。典型的 Python 惯用法是用内置的 range() 函数生成所有的序列下标: for i in range(mylist_length): do_something(mylist[i]) 其实这种实现也并不 Pythonic,接下来大家看看语言推荐的实现方式,真正 Pythonic 实现: for element in mylist: do_something(element) “如何直接传递或改变引用”是comp.lang.python 的“月经贴”,但在只有赋值(import、class、def 等语句也可视为赋值)的 Python 中这是不可能的。这种需求通常是因为想让函数返回多个值,用 C 或者许多其它编程语言的方法是给这个函数传入引用或指针: void foo(int* a, float* b) { *a = 3; *b = 5.5; } ... int alpha; int beta; foo( alpha, beta); 在 Python 中可以用很囧很恶心的方法来实现:通过给函数传递序列参数来返回结果。写出来的代码可能像这样: def foo(a, b): a[0] = 3 b[0] = 5.5 alpha = [0] beta = [0] foo(alpha, beta) alpha = alpha[0] beta = beta[0] 显然这是毫无 Pythonic 可言的实现。Python 中让函数返回多个值的惯用法与此迥异,得益于元组和元组解包,它看起来也要漂亮得多: def foo(): return 3, 5.5 alpha, beta = foo() 在经验老到的 Python 程序员看来,不够 Pythonic 的代码往往看起来古怪而且累赘,过于冗余也难以理解。因为它使用冗长的代码代替常见的、公认的、简短的惯用法来实现预期效果。更甚于此的是在语言支持正确的惯用法之后,非推荐的代码通常执行起来更慢。 Pythonic 就是以清晰、可读的惯用法应用Python 理念和数据结构。举个例子,应该多使用动态类型,在无必要之处引入静态类型就走向了另一端。另外也要避免使用经验丰富的 Python 程序员不熟悉的方式去完成任务(即遵循最小惊奇原则)。 Pythonic 一词也能够适用于底层的惯用法。一个 Pythonic 的库或框架能使程序员更加容易、更加自然地学会利用它来完成任务。如果用 Python 编写的库或框架迫使程序员编写累赘的或不推荐的代码,那么可以说它并不Pythonic。也许可能是为了使这个库更加方便、易懂,而没有应用 Python 的一些理念,如类等,那也是不 Pythonic 的。类定义应当尽可能地实现信息隐藏,虽然 Python 的许多操作都只作“宽松限制”(通常由程序员在属性的前面加上一个下划线来暗示这是私有成员),但也要做得像 Java 那样严格。 当然,当规模很大的时候,它是否 Pythonic 就极具争议性了。这里给出一些参考条款:如减少冗余,Python 的库与 APIs 都倾向于小型化和轻量化(相对于 java 程序库而言)。重量级的、API过于细化的的Python 库并不 Pythonic。比如 W3C XML DOM API,尽管它的 Python 实现已经颇有时日,但大家并不认为它 Pythonic。有些人认为它是 Java 式的,虽然也有许多 Java 程序员认为并不如此。 一个Pythonic的框架不会对已经用惯用法完成的东西重复发明轮子,而且它也遵循常用的 Python 惯例。 当然,问题是构建框架时肯定会不可能避免地引入一些你不熟悉的模式和方法。Zope2 是我极为熟悉的一个框架,它也是一个引入了许多完成工作的特定的方法(如 Acquisition)的例子,这些方法往往什么地方都用不到,因此许多经验丰富的 Python 程序员认为它并不 Pythonic。 创建 Pythonic 的框架极其困难,什么理念更酷、更符合语言习惯对此毫无帮助,事实上这些年来优秀的 Python 代码的特性也在不断演化。比如现在认为像 generators、sets、unicode strings 和 datetime 之类的特性尤为 Pythonic。Zope2 的历史悠久,它从1997年开始开发,你不能把不够 Pythonic 归咎于它,甚至考虑到这么多年来它控制得如此之好,更应该感谢它。 关于 Pythonicness 的新趋势的一个例子是Python 的包和模块结构日益规范化。新的代码库如 Twisted、Zope3 和 PyPy 等或多或少都跟随了这样的潮流: 包和模块的命名采用小写,单数形式,而且短小。 包通常仅仅作为命名空间,如只包含空的 __init__.py 文件。 在我写库( ...

阅读全文 »

Code Like a Pythonista: Idiomatic Python(像python高手一样编程:地道的python)

Python 的禅(1) 这些是python的指导原则,但是诠释是开放的。对这些原则合适的解释是需要一些幽默感的。如果你正在使用以小品喜剧艺术团的名字命名的一种编程语言,你最好具有幽默感。 Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. ... Python 的禅(2) In the face of ambiguity, refuse the temptation to guess. There should be one—and preferably only one—obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than right now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea—let's do more of those! 这首特别的“诗”开始作为一个笑话,但它确实包含了很多关于Python背后的哲学真理。 Python的禅已经正式成文PEP 20,它的摘要是: Python老手Tim Peters 把BDFL(http://en.wikipedia.org/wiki/BDFL)的python代码设计的指导原则简洁地总结成20条格言,只有19条被记录下来。 如果你是一个“Pythoneer”或“Pythonista”,你可以自己决定,python的禅有不同的内涵。 如果存在疑问: Import this 尝试在Python交互式解释: import this Python中还有一个复活节彩蛋: from __future__ import braces   File " stdin ", line 1 SyntaxError: not a chance 一群喜剧演员! 编程风格:读胜于写 程序必须是写来给人读得,只是顺带让机器执行。 —Abelson Sussman, 计算机 程序的构造 和解释 尽量让你的程序易于阅读和明显。 PEP 8 :Python 代码风格指南 值得阅读: http://www.python.org/dev/peps/pep-0008/ PEP=Python的增强建议 一个PEP是向python社区提供信息的设计文档,或描述Python或过程或环境的新功能。 Python社区有着自己的代码风格的标准,这些标准编纂在PEP 8中。这些标准是与其他社区的不同,如C,C +,C#,Java,VisualBasic等等。 因为缩进和空格在python中至关重要,Python代码风格指南几乎就是标准。遵循风格指南是将是十分明智。大多数开源项目和内部项目紧紧地遵循风格指南。 空格1 4个空格一个缩进层次; 最好不要使用制表符; 永远不要混用制表符和空格;( 这确实是IDLE和Emacs的Python模式的支持。 其他编辑器也可以提供这种支持。) 函数之间使用一个空行分割; 类之间使用两个空行分割 空格2 添加一个空格在字典、列表、序列、参数列表中的“,“后,以及在字典中的”:“之后,而不是之前; 在赋值和比较两边放置一个空格(参数列表中除外); 紧随括号后面或者参数列表前一个字符不要存在空格; (a, b) yes   (  a, b)    no Def test(a, b, c): pass   yes Def test(  a, b, c)      no 紧随文档字符串的后面不要存在空格; “””Return a”””  yes    “”” Return a””” no def make_squares(key, value=0):     """Return a dictionary and a list..."""     d = {key: value}     l = [key, value]     return d, l 命名 l  应避免的名字 永远不要用字符`l'(小写字母el(就是读音,下同)), O'(大写字母oh),或I'(大写字母eye)作为单字符的变量名. 在某些字体中,这些字符不能与数字1和0分开.当想要使用'l'时,用'L'代替它. l  模块名 模块应该是不含下划线的,简短的,小写的名字. 因为模块名被映射到文件名, 有些文件系统大小写不敏感并且截短长名字, 模块名被选为相当短是重要的---这在Unix上不是问题, 但当代码传到Mac 或Windows上就可能是个问题了. 当一个用C或C++写的扩展模块有一个伴随的Python模块,这个Python模块提供了 一个更高层(例如,更面向对象)的接口时,C/C++模块有一个前导下划线(如:_socket) Python包应该是不含下划线的,简短的,全小写的名字. l  类名 几乎没有例外,类名总是使用首字母大写单词串(CapWords)的约定. l  异常名 如果模块对所有情况定义了单个异常,它通常被叫做"error"或"Error". 似乎内建(扩展)的模块使用"error"(例如:os.error), 而Python模块通常用"Error" (例如: xdrlib.Error). 趋势似乎是倾向使用CapWords异常名. l  全局变量名 (让我们希望这些变量打算只被用于模块内部) 这些约定与那些用于函数的约定差不多.被设计可以通过"from M import *"来使用的 那些模块,应该在那些不想被导入的全局变量(还有内部函数和类)前加一个下划线). l  函数名 函数名应该为小写,可能用下划线风格单词以增加可读性. mixedCase仅被允许用于这种风格已经占优势的上下文(如: threading.py) 以便保持向后兼容. l  ...

阅读全文 »

Python装饰器的理解 (转载)

装饰器一直不是很容易理解,在网上找了一篇文章对装饰器的解释是最好的。转给大家以共享。 Python中函数有一个装饰器的概念,今天,看核心编程中的函数一章的时候接触到了这个概念,炸一看来,讲的说明真实不好明白。于是写下本篇以示说明,提供给迷糊者。希望能对一些人起到一定的帮助 装饰器的语法以@开头,接着是装饰器要装饰的函数的申明等。 其实总体说起来,装饰器其实也就是一个函数,一个用来包装函数的函数,装饰器在函数申明完成的时候被调用,调用之后申明的函数被换成一个被装饰器装饰过后的函数。 装饰器分为无参装饰和有参装饰 无参装饰很简单 定义方法如下: 比如先定义一个装饰方法: def FirstDeco(func): print '第一个装饰器' return func @FirstDeco def test(): print 'asdf' .... 申明完成之后显示 ... 第一个装饰器 可见装饰器在函数定义完成的时候被触发 然后,咱们运行test 获得asdf 多参装饰: 多参装饰复杂一点,多参装饰的时候,装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰 具体代码如下: def deco(x): ... print '%s 开始新装饰' ... def newDeco(func): ... def test(a,b): ... print 'begin' ... returnv = func(a,b) ... print 'end' ... return returnv ... return test ... return newDeco ... 这里定义了一个装饰其函数deco,里面有一个参数x,这个时候,我们没有直接使用func作为装饰函数的参数,而是只用了参数x作为参数,之后定义一个新的装饰函数,newdeco,该函数才装饰 然后定义如下: @deco(3) ... def mytest(x,y): ... if x y: ... print x ... else: ... print y ... %s 开始新装饰 运行之后的结果为 %s 开始新装饰 mytest(3,4) begin 4 end 参考资料: 装饰方法的产生: Python2.2通过增加静态方法和类方法扩展了Python的对象模型。但是当时没有提供一个简化的语法去定义static/class方法,只得在定义好的方法尾部去调用staticmethod()/classmethod()方法达到目的。例如: class C: def meth (cls):meth = classmethod(meth) # 使meth方法成为类方法 但是这样会造成一个问题:当一个方法比较长时,很容易忘记尾部的调用。为了简化这个操作一个新的语法被加了进来:方法装饰,以@开头后跟装饰方法 名,如@staticmethod/@classmethod,由此产生出decorator方法及decorator模式。现在我们可以这样写: class C: @classmethod def meth (cls): 可以对一个方法应用多个装饰方法: @A @B @C def f ():#等价于下面的形式,Python会按照应用次序依次调用装饰方法(最近的先调用) def f(): f = A(B(C(f))) 装饰方法解析: 每个decorator只是一个方法, 可以是自定义的或者内置的(如内置的@staticmethod/@classmethod)。decorator方法把要装饰的方法作为输入参数,在函数体内可以进行任意的操作(可以想象其中蕴含的威力强大,会有很多应用场景), 只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数, 或者是一个新函数)。decorator的作用对象可以是模块级的方法或者类方法。decorator根据应用时的参数个数不同分为两类:无参数 decorator,有参数decorator。下面分别介绍。 无参数decorator: def deco(func): """无参数调用decorator声明时必须有一个参数,这个参数将接收要装饰的方法""" print "Enter decorator" #进行额外操作 func.attr = 'decorated' #对函数进行操作,增加一个函数属性 return func #返回一个可调用对象(此例还是返回作为输入参数的方法) #返回一个新函数时,新函数可以是一个全局方法或者decorator函数的内嵌函数, #只要函数的签名和被装饰的函数相同@deco def MyFunc(): #应用@deco修饰的方法 print "Enter MyFunc" MyFunc() #调用被装饰的函数 注意:当使用上述方法定义一个decorator方法时,函数体内的额外操作只在被装饰的函数首次调用时执行,如果要保证额外操作在每次调用被装饰的函数时都执行,需要换成如下的写法: def deco(func): def replaceFunc(): #定义一个内嵌函数,此函数包装了被装饰的函数,并提供额外操作的代码 print "Enter decorator" #进行额外操作 return func() #产生对被装饰函数的调用 return replaceFunc #由于返回的是这个新的内嵌函数,所以确保额外操作每次调用得以运行@deco def MyFunc(): #应用@deco修饰的方法 print "Enter MyFunc" MyFunc() #调用被装饰的函数 有参数decorator: def decoWithArgs(arg): """由于有参数的decorator函数在调用时只会使用应用时的参数而不接收被装饰的函数做为参数, 所以必须返回一个decorator函数, 由它对被装饰的函数进行封装处理""" def newDeco(func): #定义一个新的decorator函数 def replaceFunc(): #在decorator函数里面再定义一个内嵌函数,由它封装具体的操作 print "Enter decorator" #进行额外操作 return func() #对被装饰函数进行调用 return replaceFunc return newDeco #返回一个新的decorator函数@decoWithArgs("demo") def MyFunc(): #应用@decoWithArgs修饰的方法 print "Enter MyFunc" MyFunc() #调用被装饰的函数 当我们对某个方法应用了装饰方法后, 其实就改变了被装饰函数名称所引用的函数代码块入口点,使其重新指向了由装饰方法所返回的函数入口点。由此我们可以用decorator改变某个原有函数的功能,添加各种操作,或者完全改变原有实现。 ...

阅读全文 »