1 if x <= y <= z:
2 return True // Python解释执行以上两种不同的比较方式时,其实都是先比较x<=y,如果为真,再比较y<=z。主要的区别在于,链式比较时,会先取y的值,然后复制压栈,整个过程中y的求值只执行了一次,而用and的方式时,y的求值会执行两次,也就是说,如果比较的是三个函数或者复杂的对象的话,链式比较只会求值三次,而通过and比较的方式则会求值4次。这大概就是为什么作者说执行效率会更好,但实际上如果只是简单的变量进行比较,效率未必会有提高。
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') 1.1.4 避免直接与True, False或者None直接比较
对于任意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 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)) 1.2.2 使用in关键字遍历可迭代结构
在没有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) 1.2.3 使用else去执行一个for循环全部遍历结束后的代码
在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地址均有效!')
转载请注明出处:達聞西@博客園
下一篇:翻译《Writing Idiomatic Python》(二):函数、异常