创建将0到19连接起来的字符串
1 2 3 4 5 6 7 8
| nums = [] for n in range(20): nums.append(str(n)) print "".join(nums)
# 更好的写法 nums = [str(n) for n in range(20)] print "".join(nums)
|
拼接多个已有的字符串
1 2 3 4 5 6 7
| foo = 'foo' bar = 'bar'
foobar = foo + bar # 好的做法
foo += 'ooo' # 不好的做法, 应该这么做: foo = ''.join([foo, 'ooo'])
|
1 2 3 4 5 6
| foo = 'foo' bar = 'bar'
foobar = '%s%s' % (foo, bar) # 可行 foobar = '{0}{1}'.format(foo, bar) # 更好 foobar = '{foo}{bar}'.format(foo=foo, bar=bar) # 最好
|
不要重复使用命名
1 2 3
| items = 'a b c d' # 首先指向字符串... items = items.split(' ') # ...变为列表 items = set(items) # ...再变为集合
|
重复使用命名对效率并没有提升:赋值时无论如何都要创建新的对象。然而随着复杂度的 提升,赋值语句被其他代码包括 ‘if’ 分支和循环分开,使得更难查明指定变量的类型。 在某些代码的做法中,例如函数编程,推荐的是从不重复对同一个变量命名赋值。Java 内的实现方式是使用 ‘final’ 关键字。Python并没有 ‘final’ 关键字而且这与它的哲学 相悖。尽管如此,避免给同一个变量命名重复赋值仍是是个好的做法,并且有助于掌握 可变与不可变类型的概念。
考虑该不该用任意参数列表(*args)
如果一个函数接受的参数列表具有 相同的性质,通常把它定义成一个参数,这个参数是一个列表或者其他任何序列会更清晰。
函数单个出口可能更好
当一个函数在其正常过程中有多个主要出口点时,它会变得难以调试和返回其 结果,所以保持单个出口点可能会更好。这也将有助于提取某些代码路径,而且多个出口点 很有可能意味着这里需要重构。
1 2 3 4 5 6 7 8 9 10 11
| def complex_function(a, b, c): if not a: return None # 抛出一个异常可能会更好 if not b: return None # 抛出一个异常可能会更好
# 一些复杂的代码试着用a,b,c来计算x # 如果成功了,抵制住返回x的诱惑 if not x: # 一些关于x的计算的Plan-B return x
|
常见Python习语
1 2 3 4 5 6
| for index, item in enumerate(some_list): # 使用index和item做一些工作 a, b = b, a
a, (b, c) = 1, (2, 3)
|
1 2
| filename = 'foobar.txt' basename, __, ext = filename.rpartition('.')
|
1
| four_lists = [[] for __ in xrange(4)]
|
1 2
| letters = ['s', 'p', 'a', 'm'] word = ''.join(letters)
|
1 2 3 4 5 6 7 8
| s = set(['s', 'p', 'a', 'm']) l = ['s', 'p', 'a', 'm']
def lookup_set(s): return 's' in s
def lookup_list(l): return 's' in l
|
在下列场合在使用集合或者字典而不是列表,通常会是个好主意:
集合体中包含大量的项
你将在集合体中重复地查找项
你没有重复的项
你不需要明确地比较一个值是True,或者None,或者0
糟糕
1 2 3 4 5
| if attr == True: print 'True!'
if attr == None: print 'attr is None!'
|
优雅
1 2 3 4 5 6 7 8 9 10 11
| # 检查值 if attr: print 'attr is truthy!'
# 或者做相反的检查 if not attr: print 'attr is falsey!'
# or, since None is considered false, explicitly check for it if attr is None: print 'attr is None!'
|
访问字典元素
糟糕
1 2 3 4 5
| d = {'hello': 'world'} if d.has_key('hello'): print d['hello'] # 打印 'world' else: print 'default_value'
|
优雅
1 2 3 4 5 6 7 8
| d = {'hello': 'world'}
print d.get('hello', 'default_value') # 打印 'world' print d.get('thingy', 'default_value') # 打印 'default_value'
# Or: if 'hello' in d: print d['hello']
|
在每次函数调用中,通过使用指示没有提供参数的默认参数 None 通常是 个好选择),来创建一个新的对象。
举例:
1 2 3
| def append_to(element, to=[]): to.append(element) return to
|
你可能认为
1 2 3 4 5
| my_list = append_to(12) print my_list # [12]
my_other_list = append_to(42) print my_other_list # [42]
|
实际结果为
当函数被定义时,一个新的列表就被创建一次 ,而且同一个列表在每次成功的调用中都被使用。
当函数被定义时,Python的默认参数就被创建 一次,而不是每次调用函数的时候创建。 这意味着,如果你使用一个可变默认参数并改变了它,你 将会 在未来所有对此函数的 调用中改变这个对象。
迟绑定闭包
举例
1 2 3 4 5
| def create_multipliers(): return [lambda x : i * x for i in range(5)] for multiplier in create_multipliers(): print multiplier(2)
|
你期望的结果
实际结果
五个函数被创建了,它们全都用4乘以 x 。
Python的闭包是 迟绑定 。 这意味着闭包中用到的变量的值,是在内部函数被调用时查询得到的。
这里,不论 任何 返回的函数是如何被调用的, i 的值是调用时在周围作用域中查询到的。 接着,循环完成, i 的值最终变成了4。
这个陷阱并不和 lambda 有关,不通定义也会这样
1 2 3 4 5 6 7 8 9
| def create_multipliers(): multipliers = []
for i in range(5): def multiplier(x): return i * x multipliers.append(multiplier)
return multipliers
|
解决方案
最一般的解决方案可以说是有点取巧(hack)。由于 Python 拥有为函数默认参数 赋值的行为,你可以创建一个立即绑定参数的闭包,像下面这样:
1 2
| def create_multipliers(): return [lambda x, i=i : i * x for i in range(5)]
|
或者,可以使用 function.partial
函数
1 2 3 4 5
| from functools import partial from operator import mul
def create_multipliers(): return [partial(mul, i) for i in range(5)]
|