利用表单大师做网站,网站备案证书放到哪里,广州有名的网站建设公司,关键词排名优化软件在Python社区文化的浇灌下#xff0c;演化出了一种独特的代码风格#xff0c;去指导如何正确地使用Python#xff0c;这就是常说的pythonic。一般说地道(idiomatic)的python代码#xff0c;就是指这份代码很pythonic。Python的语法和标准库设计#xff0c;处处契合着pytho…在Python社区文化的浇灌下演化出了一种独特的代码风格去指导如何正确地使用Python这就是常说的pythonic。一般说地道(idiomatic)的python代码就是指这份代码很pythonic。Python的语法和标准库设计处处契合着pythonic的思想。而且Python社区十分注重编码风格一的一致性他们极力推行和处处实践着pythonic。所以经常能看到基于某份代码P vs NP (pythonic vs non-pythonic)的讨论。pythonic的代码简练明确优雅绝大部分时候执行效率高。阅读pythonic的代码能体会到“代码是写给人看的只是顺便让机器能运行”畅快。然而什么是pythonic就像什么是地道的汉语一样切实存在但标准模糊。import this可以看到Tim Peters提出的Python之禅它提供了指导思想。许多初学者都看过它深深赞同它的理念但是实践起来又无从下手。PEP 8给出的不过是编码规范对于实践pythonic还远远不够。如果你正被如何写出pythonic的代码而困扰或许这份笔记能给你帮助。Raymond Hettinger是Python核心开发者本文提到的许多特性都是他开发的。同时他也是Python社区热忱的布道师不遗余力地传授pythonic之道。这篇文章是网友Jeff Paine整理的他在2013年美国的PyCon的演讲的笔记。术语澄清本文所说的集合全都指collection而不是set。以下是正文。本文是Raymond Hettinger在2013年美国PyCon演讲的笔记(视频, 幻灯片)。示例代码和引用的语录都来自Raymond的演讲。这是我按我的理解整理出来的希望你们理解起来跟我一样顺畅遍历一个范围内的数字foriin[0,1,2,3,4,5]:printi ** 2foriinrange(6):printi ** 2更好的方法foriinxrange(6):printi ** 2xrange会返回一个迭代器用来一次一个值地遍历一个范围。这种方式会比range更省内存。xrange在Python 3中已经改名为range。遍历一个集合colors [red,green,blue,yellow]foriinrange(len(colors)):print colors[i]更好的方法forcolor incolors:print color反向遍历colors [red,green,blue,yellow]foriinrange(len(colors)-1,-1,-1):print colors[i]更好的方法forcolor inreversed(colors):print color遍历一个集合及其下标colors [red,green,blue,yellow]foriinrange(len(colors)):printi,---,colors[i]更好的方法fori,color inenumerate(colors):printi,---,color这种写法效率高优雅而且帮你省去亲自创建和自增下标。当你发现你在操作集合的下标时你很有可能在做错事。遍历两个集合names [raymond,rachel,matthew]colors [red,green,blue,yellow]n min(len(names),len(colors))foriinrange(n):print names[i],---,colors[i]forname,color inzip(names,colors):print name,---,color更好的方法forname,color inizip(names,colors):print name,---,colorzip在内存中生成一个新的列表需要更多的内存。izip比zip效率更高。注意在Python 3中izip改名为zip并替换了原来的zip成为内置函数。有序地遍历colors [red,green,blue,yellow]# 正序forcolor insorted(colors):print colors# 倒序forcolor insorted(colors,reverseTrue):print colors自定义排序顺序colors [red,green,blue,yellow]def compare_length(c1,c2):iflen(c1)iflen(c1) len(c2): return1return0print sorted(colors,cmpcompare_length)更好的方法print sorted(colors, keylen)第一种方法效率低而且写起来很不爽。另外Python 3已经不支持比较函数了。调用一个函数直到遇到标记值blocks []whileTrue:block f.read(32)ifblock :breakblocks.append(block)更好的方法blocks []forblock initer(partial(f.read,32),):blocks.append(block)iter接受两个参数。第一个是你反复调用的函数第二个是标记值。译注这个例子里不太能看出来方法二的优势甚至觉得partial让代码可读性更差了。方法二的优势在于iter的返回值是个迭代器迭代器能用在各种地方setsortedminmaxheapqsum……在循环内识别多个退出点def find(seq,target):found Falsefori,value inenumerate(seq):ifvalue target:found Truebreakifnotfound:return-1returni更好的方法def find(seq,target):fori,value inenumerate(seq):ifvalue target:breakelse:return-1returnifor执行完所有的循环后就会执行else。译注刚了解for-else语法时会困惑什么情况下会执行到else里。有两种方法去理解else。传统的方法是把for看作if当for后面的条件为False时执行else。其实条件为False时就是for循环没被break出去把所有循环都跑完的时候。所以另一种方法就是把else记成nobreak当for没有被break那么循环结束时会进入到else。遍历字典的keyd {matthew: blue,rachel: green,raymond: red}forkind:printkforkind.keys():ifk.startswith(r):deld[k]什么时候应该使用第二种而不是第一种方法当你需要修改字典的时候。如果你在迭代一个东西的时候修改它那就是在冒天下之大不韪接下来发生什么都活该。d.keys()把字典里所有的key都复制到一个列表里。然后你就可以修改字典了。注意如果在Python 3里迭代一个字典你得显示地写list(d.keys())因为d.keys()返回的是一个“字典视图”(一个提供字典key的动态视图的迭代器)。详情请看文档。遍历一个字典的key和value# 并不快每次必须要重新哈希并做一次查找forkind:printk,---,d[k]# 产生一个很大的列表fork,vind.items():printk,---,v更好的方法fork,vind.iteritems():printk,---,viteritems()更好是因为它返回了一个迭代器。注意Python 3已经没有iteritems()了items()的行为和iteritems()很接近。详情请看文档。用key-value对构建字典names [raymond,rachel,matthew]colors [red,green,blue]d dict(izip(names,colors))# {matthew: blue, rachel: green, raymond: red}Python 3: d dict(zip(names, colors))用字典计数colors [red,green,red,blue,green,red]# 简单基本的计数方法。适合初学者起步时学习。d {}forcolor incolors:ifcolor notind:d[color] 0d[color] 1# {blue: 1, green: 2, red: 3}更好的方法d {}forcolor incolors:d[color] d.get(color,0) 1# 稍微潮点的方法但有些坑需要注意适合熟练的老手。d defaultdict(int)forcolor incolors:d[color] 1用字典分组 — 第I部分和第II部分names [raymond,rachel,matthew,roger,betty,melissa,judith,charlie]# 在这个例子我们按name的长度分组d {}forname innames:key len(name)ifkey notind:d[key] []d[key].append(name)# {5: [roger, betty], 6: [rachel, judith], 7: [raymond, matthew, melissa, charlie]}d {}forname innames:key len(name)d.setdefault(key,[]).append(name)更好的方法d defaultdict(list)forname innames:key len(name)d[key].append(name)字典的popitem()是原子的吗d {matthew: blue,rachel: green,raymond: red}whiled:key,value d.popitem()print key,--,valuepopitem是原子的所以多线程的时候没必要用锁包着它。连接字典defaults {color: red,user: guest}parser argparse.ArgumentParser()parser.add_argument(-u,--user)parser.add_argument(-c,--color)namespace parser.parse_args([])command_line_args {k: vfork,vinvars(namespace).items()ifv}# 下面是通常的作法默认使用第一个字典接着用环境变量覆盖它最后用命令行参数覆盖它。# 然而不幸的是这种方法拷贝数据太疯狂。d defaults.copy()d.update(os.environ)d.update(command_line_args)更好的方法d ChainMap(command_line_args, os.environ, defaults)ChainMap在Python 3中加入。高效而优雅。提高可读性位置参数和下标很漂亮但关键字和名称更好第一种方法对计算机来说很便利第二种方法和人类思考方式一致用关键字参数提高函数调用的可读性twitter_search(obama, False, 20, True)更好的方法twitter_search(obama, retweetsFalse, numtweets20, popularTrue)第二种方法稍微(微秒级)慢一点但为了代码的可读性和开发时间值得。用namedtuple提高多个返回值的可读性# 老的testmod返回值doctest.testmod()# (0, 4)# 测试结果是好是坏你看不出来因为返回值不清晰。更好的方法# 新的testmod返回值, 一个namedtupledoctest.testmod()# TestResults(failed0, attempted4)namedtuple是tuple的子类所以仍适用正常的元组操作但它更友好。创建一个nametupleTestResults namedTuple(TestResults, [failed, attempted])unpack序列p Raymond,Hettinger,0x30,pythonexample.com# 其它语言的常用方法/习惯fname p[0]lname p[1]age p[2]email p[3]更好的方法fname, lname, age, email p第二种方法用了unpack元组更快可读性更好。更新多个变量的状态def fibonacci(n):x 0y 1foriinrange(n):printxt yy x yx t更好的方法def fibonacci(n):x,y 0,1foriinrange(n):printxx,y y,x y第一种方法的问题x和y是状态状态应该在一次操作中更新分几行的话状态会互相对不上这经常是bug的源头。操作有顺序要求太底层太细节第二种方法抽象层级更高没有操作顺序出错的风险而且更效率更高。同时状态更新tmp_x x dx *ttmp_y y dy *ttmp_dx influence(m,x,y,dx,dy,partialx)tmp_dy influence(m,x,y,dx,dy,partialy)x tmp_xy tmp_ydx tmp_dxdy tmp_dy更好的方法x,y,dx,dy (x dx *t,y dy *t,influence(m,x,y,dx,dy,partialx),influence(m,x,y,dx,dy,partialy))效率优化的基本原则除非必要别无故移动数据稍微注意一下用线性的操作取代O(n**2)的操作总的来说不要无故移动数据连接字符串names [raymond,rachel,matthew,roger,betty,melissa,judith,charlie]s names[0]forname innames[1:]:s , nameprints更好的方法print , .join(names)更新序列names [raymond,rachel,matthew,roger,betty,melissa,judith,charlie]del names[0]# 下面的代码标志着你用错了数据结构names.pop(0)names.insert(0,mark)更好的方法names deque([raymond,rachel,matthew,roger,betty,melissa,judith,charlie])# 用deque更有效率del names[0]names.popleft()names.appendleft(mark)装饰器和上下文管理用于把业务和管理的逻辑分开分解代码和提高代码重用性的干净优雅的好工具起个好名字很关键记住蜘蛛侠的格言能力越大责任越大使用装饰器分离出管理逻辑# 混着业务和管理逻辑无法重用def web_lookup(url,saved{}):ifurl insaved:returnsaved[url]page urllib.urlopen(url).read()saved[url] pagereturnpage更好的方法cachedef web_lookup(url):returnurllib.urlopen(url).read()注意Python 3.2开始加入了functools.lru_cache解决这个问题。分离临时上下文# 保存旧的创建新的old_context getcontext().copy()getcontext().prec 50print Decimal(355)/ Decimal(113)setcontext(old_context)更好的方法with localcontext(Context(prec50)):print Decimal(355)/ Decimal(113)译注示例代码在使用标准库decimal这个库已经实现好了localcontext。如何打开关闭文件f open(data.txt)try:data f.read()finally:f.close()更好的方法with open(data.txt)asf:data f.read()如何使用锁# 创建锁lock threading.Lock()# 使用锁的老方法lock.acquire()try:printCritical section 1printCritical section 2finally:lock.release()更好的方法# 使用锁的新方法with lock:printCritical section 1printCritical section 2分离出临时的上下文try:os.remove(somefile.tmp)except OSError:pass更好的方法with ignored(OSError):os.remove(somefile.tmp)ignored是Python 3.4加入的, 文档。注意ignored 实际上在标准库叫suppress(译注contextlib.supress).试试创建你自己的ignored上下文管理器。contextmanagerdef ignored(*exceptions):try:yieldexcept exceptions:pass把它放在你的工具目录你也可以忽略异常译注contextmanager在标准库contextlib中通过装饰生成器函数省去用__enter__和__exit__写上下文管理器。详情请看文档。分离临时上下文# 临时把标准输出重定向到一个文件然后再恢复正常with open(help.txt,w)asf:oldstdout sys.stdoutsys.stdout ftry:help(pow)finally:sys.stdout oldstdout更好的写法with open(help.txt,w)asf:with redirect_stdout(f):help(pow)redirect_stdout在Python 3.4加入(译注contextlib.redirect_stdout) bug反馈。实现你自己的redirect_stdout上下文管理器。contextmanagerdef redirect_stdout(fileobj):oldstdout sys.stdoutsys.stdout fileobjtry:yield fieldobjfinally:sys.stdout oldstdout简洁的单句表达两个冲突的原则一行不要有太多逻辑不要把单一的想法拆分成多个部分Raymond的原则一行代码的逻辑等价于一句自然语言列表解析和生成器result []foriinrange(10):s i ** 2result.append(s)print sum(result)更好的方法print sum(i**2 for i in xrange(10))第一种方法说的是你在做什么第二种方法说的是你想要什么。来源www.lightxue.com/transforming-code-into-beautiful-idiomatic-python 侵删。