这是在美国Amazon上评价很不错的一本书,其实严格来讲这可能不算书,而是一本小册子。就像书名同样,里面的内容主要是用一些例子讲述地道的Python的代码是怎样写的。书中把不少例子用不良风格和地道Python写法做对比,内容覆盖谈不上很全,可是每一条都颇有表明性。整体而言很是适合新手,同时里面有些条目老手看了或许也会有豁然开朗的感受。做者Jeff Knupp曾在全球最牛B的高盛和其余银行里作过金融系统开发,在北美Python社区里也颇有活跃度。html
本身用Python也有些年头了,作过一年多的商业开发,不过其余大部分仍是以科研和预研期的算法为主。最近由于又开始用Python作商业开发,因此想着顺便找些书看看,无心中看到了这本小书,以为很不错,国内没有卖的,更别提中文版了。翻译这本书,算是复习和从新思考下Python,同时也会有少许本身的看法(C++风格注释绿色粗体),但愿能坚持下去吧。我看的版本主要分为四部分:Control Structures and Functions(控制结构和函数)、Working with Data(数据和类型)、Organizing Your Code(代码组织)、General Advice(通常性建议)。每一部分里又分为不一样的小章节,一共二十几个。我会按这个顺序不按期放出数目不定的章节。本人英文水平尚可,不过没有翻译经验,虽然不知道会不会有人关注这个系列,仍是但愿若是有看官,请轻拍指正:)python
原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/算法
下一篇:翻译《Writing Idiomatic Python》(二):函数、异常安全
当使用if语句时,优先使用链式比较操做,不只会让语句更加简明,也会让执行效率更好。ide
不良风格:函数
1 if x <= y and y <= z: 2 return True
地道Python:post
1 if x <= y <= z: 2 return True
// Python解释执行以上两种不一样的比较方式时,其实都是先比较x<=y,若是为真,再比较y<=z。主要的区别在于,链式比较时,会先取y的值,而后复制压栈,整个过程当中y的求值只执行了一次,而用and的方式时,y的求值会执行两次,也就是说,若是比较的是三个函数或者复杂的对象的话,链式比较只会求值三次,而经过and比较的方式则会求值4次。这大概就是为何做者说执行效率会更好,但实际上若是只是简单的变量进行比较,效率未必会有提升。url
使用缩进来表示代码块的结构会让人更容易判断条件分支的代码结构。if,elif和else语句应该都老是独占一行,在冒号后没有代码。spa
不良风格:翻译
1 name = 'Jeff' 2 address = 'New York, NY' 3 4 if name: print(name) 5 print(address)
地道Python:
1 name = 'Jeff' 2 address = 'New York, NY' 3 4 if name: 5 print(name) 6 print(address)
// 文件中的代码应该遵循这个规则,在控制台下放一行也何尝不可
当想用if语句检查一个变量是否和许多值中的一个相等时,用==和or重复写许多遍是否相等的检查会显得代码很冗长。简洁的写法是判断该变量是否在一个可遍历的结构中。
不良风格:
1 is_generic_name = False 2 name = 'Tom' 3 if name == 'Tom' or name == 'Dick' or name == 'Harry': 4 is_generic_name = True
地道Python:
1 name = 'Tom' 2 is_generic_name = name in ('Tom', 'Dick', 'Harry')
对于任意Python中的对象,不管是内建的仍是用户定义的,自己都会关联一个内部的“真值”(truthiness)。因此很天然地,当判断一个条件是否为真的时候,尽可能在条件判断语句中优先依靠这个隐式的“真值”。下面列举的是“真值”为False的状况:
None
False
数值0
空的序列(列表,元组等)
空的字典
当__len__或者__nonzero__被调用后返回的0值或者False
按照上面的最后一条,经过检查调用__len__或者__nonzero__后返回的值的方式,咱们也能够定义本身建立的类型的“真值”。除了上面列举的这些,其余的状况都被认为“真值”为True。
在Python中if语句隐式地使用“真值”,因此你的代码中也应该这样作。好比对于下面这种写法:
if foo == True:
更简单而直接的写法是:
if foo:
这样作的理由有不少。最明显的一条理由是,若是你的代码发生了变化,好比当foo变成了一个int型而不是True或False,if语句在判断是否为0时仍然正确。在更深的层面上,这是基于相等性(equality)和等价性(identity)的差异。使用==检查的是两个对象是否有相等或是等效的值(由_eq属性定义),而is语句则检查的是两个对象在底层是否同一个对象。
// Python对相等的实如今C代码中实现将比较对象用PyInt_AS_LONG转化成long型,而后再用C中的==进行比较,而is的实现是直接==比较。
因此对False,None和和空的序列好比[], {},以及()应该避免直接进行比较。若是一个叫my_list的列表为空, if my_list 会判断为False。固然有些状况下,虽然不推荐,可是直接和None比较是必须的。当在一个函数中须要判断一个默认值为None的参数是否被赋值的时候,好比:
1 def insert_value(value, position=None): 2 """向自定义的容器中插入一个值,插入值 3 的位置做为可选参数,默认值为None""" 4 if position is not None: 5 ...
若是使用 if position: 的话,哪里会出错呢?设想若是有人想在0位置插入一个值,那么函数会认为position这个参数没有设置,由于 if 0: 会断定为False。注意这里使用的是is not,根据PEP8,和None比较应该老是用is或者is not而不是==
总之,就让Python的“真值”代替你作比较的工做。
不良风格:
1 def number_of_evil_robots_attacking(): 2 return 10 3 4 def should_raise_shields(): 5 # 只有当一只以上的巨型机器人进攻时才打开防御罩 6 # 因此我只须要返回巨型机器人的数量,若是不为零会自动判断为真 7 return number_of_evil_robots_attacking() 8 9 if should_raise_shields() == True: 10 raise_shields() 11 print('防御罩已打开') 12 else: 13 print('安全!并无巨型机器人在进攻')
地道Python:
1 def number_of_evil_robots_attacking(): 2 return 10 3 4 def should_raise_shields(): 5 # 只有当一只以上的巨型机器人进攻时才打开防御罩 6 # 因此我只须要返回巨型机器人的数量,若是不为零会自动判断为真 7 return number_of_evil_robots_attacking() 8 9 if should_raise_shields(): 10 raise_shields() 11 print('防御罩已打开') 12 else: 13 print('安全!并无巨型机器人在进攻')
和许多其余语言不一样,Python没有三元操做符(好比: x ? true : false)。不过Python能够将赋值推迟到条件判断以后,因此在Python中三元操做能够用条件判断来替代。固然须要注意的是,除非是很简单的语句,不然三元操做的替代方案会让语句的可读性下降。
不良风格:
1 foo = True 2 value = 0 3 4 if foo: 5 value = 1 6 7 print(value)
地道Python:
1 foo = True 2 3 value = 1 if foo else 0 4 5 print(value)
在许多其余语言中,开发者习惯显式地声明一个变量用来做为循环中的计数或者相关容器的索引。例如在C++中:
1 for ( int i = 0; i < container.size(); ++i ) 2 { 3 // Do stuff 4 }
在Python中,内置的enumerate函数就能够很天然地处理这种须要。
不良风格:
1 my_container = ['Larry', 'Moe', 'Curly'] 2 index = 0 3 for element in my_container: 4 print('{} {}'.format(index, element)) 5 index += 1
地道Python:
1 my_container = ['Larry', 'Moe', 'Curly'] 2 for index, element in enumerate(my_container): 3 print('{} {}'.format(index, element))
在没有for_each风格的语言中,开发者习惯于用索引(下标)来遍历一个容器中的元素。而在Python中,这种操做能够经过in关键字来更为优雅地实现。
不良风格:
1 my_list = ['Larry', 'Moe', 'Curly'] 2 index = 0 3 while index < len(my_list): 4 print(my_list[index]) 5 index += 1
地道Python:
1 my_list = ['Larry', 'Moe', 'Curly'] 2 for element in my_list: 3 print(element)
在Python的for循环中能够包含一个else分句,这是一个很少人知道的技巧。else语句块会在for循环中的迭代结束后执行,除非在迭代过程当中循环由于break语句结束。利用这种写法咱们能够在循环中执行条件检查。要么在要检查的条件语句为真时用break语句中止循环,要么在循环结束后进入else语句块并执行条件未被知足的状况下要执行的动做。这样作避免了在循环中单独使用一个标示变量来检查条件是否被知足。
不良风格:
1 for user in get_all_users(): 2 has_malformed_email_address = False 3 print('检查 {}'.format(user)) 4 for email_address in user.get_all_email_addresses(): 5 if email_is_malformed(email_address): 6 has_malformed_email_address = True 7 print('包含恶意email地址!') 8 break 9 if not has_malformed_email_address: 10 print('全部email地址均有效!')
地道Python:
1 for user in get_all_users(): 2 print('检查 {}'.format(user)) 3 for email_address in user.get_all_email_addresses(): 4 if email_is_malformed(email_address): 5 print('包含恶意email地址!') 6 break 7 else: 8 print('全部email地址均有效!')
转载请注明出处:達聞西@博客園