Python Idioms and Efficiency

一 要写出容易读的程序,应该使用什么样的风格(idioms)

读 the python cookbook ,尤其是前几章。那里有优秀的python风格的代码。

Build strings  as a list  and use ''.join at the end 。

join是由分隔符调用的字符串方法,而不是由list调用的。可以使用空串作为连接符来调用join方法,这是python比较怪异的地方。之所以如此,是因为,使用“+”操作符消耗的时间二次的而不是线性的。

Wrong: for s in strings: result += s
Right: result = ''.join(strings)


Always use an object's capabilities instead of its type。

python是一门动态类型的语言。你无需关心一个对象的类型,而只需要关心该对象是不是支持特定的接口操作即可。这个特性给你带来了方便的多态性。例如,在我的代码中,我会使用下面的方法检查一个字符串是否是字母组成的:

for char in string:
if char not in alphabet:
raise ValueError, "Char %s not in alphabet %a" % (char, alphabet)

只要alphabet 支持__contains__方法即可,而无需关心它是字符串,字典还是列表。

Use in whererver possible.

在自己的类中,可以通过覆盖__contains__方法来支持x in y 的操作,通过覆盖__iter__的方法来支持x in y。这样可以保证你的代码的通用性和多态性。

Better: for key in d: print key     #also works for arbitrary sequence
Worse: for key in d.keys(): print key #limited to objects with keys()
Better: if key not in d: d[key] = []
Worse: if not dict.has_key(key): d[key] = []

注意:如果你想改变一个字典,你仍然需要使用d.keys()。for key in d: del d[key]回引起RuntimeError,是因为在使用迭代器的时候改变了字典的大小。可以这样操作:for key in d.keys(): del d[key] 

Use coercion if an object must be a particuar type. 如果x必须是生日那个类型才能工作的时候,可以使用str(x)代替isinstance(str,x),可以使用try/catch来捕获转换中出现的错误。

Use if not x instead of instead of if x == 0 or if x == "" or if x == None or if x == False ,likewise,if x instead of if x != 0, if x != None 。

Use string methods rather than the string module 。

使用string的方法,而不是string模块。例如,使用s.startswith('abc')而不是startswith(s, 'abc')。这样可以避免模块间方法的冲突。

Use for line in infile, not for line in infile.readlines()。

readlines 和xreadlines 从2.3起被废弃了,转而使用新的迭代模式。for line in infile 的方式允许infile是任何可以作为文本行序列的对象。对于for line in lines ,你不用关心lines 是来自文件,还是字符串列表,或者是其他迭代器,字典的键值等等。

To reverse_sort a list

反转排序一个列表,可以如下实现:

list.sort()

list.reverse()

Use 'while 1:' for infinite loops

使用while 1代替死循环,也可以用其实想do while的功能

while 1:
curr_line = reader.next()
if not curr_line:
break
curr_line.process()

EAFP ('easier to ask forgiveness than permission')

使用捕获异常来代替避免错误的发生,即,让问题及早的出现,然后通过异常对其处理。

Worse:
#check whether int conversion will raise an error
if not isinstance(s, str) or not s.isdigit:
return None
elif len(s) > 10: #too many digits for int conversion
return None
else:
return int(str)

Better:
try:
return int(str)
except (TypeError, ValueError, OverflowError): #int conversion failed
return None

Catch only the approprite errors.

只捕获相关的异常。为了实现正确处理异常,对于不同的异常应该有不同的捕获处理

swap values without using temporary variables.

使用a, b = b, a来交换ab的值

Use zip to get a list's item with their indices

通过zip来获取列表的元素及其位置索引。

indices = xrange(maxint)    #only need this once; mine is in Utils.py
for d, index in zip(data, indices):
#do something with d and index here

二:怎么写出更快的程序

Alvays profile befor you optimize for speed.

在优化前通过使用profile.py找到程序的瓶颈所在。

Always use a good algorithm when ti is available .

算法。

Use the simplest option that could possible work.

只要能满足工作需求,越简单越好。

Build strings as a list and use  ''.join at the end。

构建一个列表,最后使用join将其连接起来。

Use tests for object identity when appropriate .

合适的时候使用python的object identity,例如使用if x not None 代替if x != None

因为前者只是检查该内存地址。

Use dictionaries (or sets)for searching ,not lists.

使用字典或者集合来进行查找,而不是列表。

Use the build-in sort wherever possible.

尽可能的使用内置的sort方法。而不是自己提供排序方法。

aux_list = [i.Count, i.Name, ... i) for i in items]
aux_list.sort() #sorts by Count, then Name, ... , then by item itself
sorted_list = [i[-1] for i in items] #extracts last item


Use map and /or filter to apply functions to lists.

使用map和filter在列表和序列上执行相应的方法。

Worse:
strings = []
for d in data:
strings.append(str(d))

Better:
strings = map(str, data)

Use list comprehentions where there are condtions attached, or where the functions are methods or take more than one parameter.

某些情况下使用列表解析效果更佳。例如:

Worse:
result = []
for d in data:
if d.Count > 4:
result.append[3*d.Count]

Better:
result = [3*d.Count for d in data if d.Count > 4]


而如果使用map,filter方法的话需要:

def triple(x):
"""Returns 3 * x.Count: raises AttributeError if .Count missing."""
return 3 * x.Count

def check_count(x):
"""Returns 1 if x.Count exists and is greater than 3, 0 otherwise."""
try:
return x.Count > 3
except:
return 0

result = map(triple, filter(check_count, data))

Use function factories to create ulility functions。

使用函数工厂的方法来创建工具方法。

http://www.oschina.net/code/snippet_70218_2436

Use the operator module and reduce to get sums, products, etc.

使用operator模块和reduce方法来获取和/乘积

Worse:
sum = 0
for d in data:
sum += d
product = 1
for d in data:
product *= d

Better:
from operator import add, mul
sum = reduce(add, data)
product = reduce(mul, data)

Use zip and dict to map fields to names.

使用zip和dict建立映射关系。

Bad:
line = 'Some GI data|Some Accession data|Some Description' #These might come from a file
fields = line.split('|')
gi = fields[0]
accession = fields[1]
description = fields[2]
#etc.
lookup = {}
lookup['GI'] = gi
lookup['Accession'] = accession
lookup['Description'] = description
#etc.

Good:
fieldnames = ['GI', 'Accession', 'Description'] #etc.
fields = line.split('|')
lookup = dict(zip(fieldnames, fields))












原文地址:https://www.cnblogs.com/macula7/p/2238141.html