翻译《Writing Idiomatic Python》(一):if语句、for循环
开篇废话
这是在美国Amazon上评价很不错的一本书,其实严格来说这可能不算书,而是一本小册子。就像书名一样,里面的内容主要是用一些例子讲述地道的Python的代码是怎样写的。书中把很多例子用不良风格和地道Python写法作对比,内容覆盖谈不上很全,但是每一条都很有代表性。总体而言非常适合新手,同时里面有些条目老手看了或许也会有豁然开朗的感觉。作者Jeff Knupp曾在全球最牛B的高盛和其他银行里做过金融系统开发,在北美Python社区里也很有活跃度。
自己用Python也有些年头了,做过一年多的商业开发,不过其他大部分还是以科研和预研期的算法为主。最近因为又开始用Python做商业开发,所以想着顺便找些书看看,无意中看到了这本小书,觉得很不错,国内没有卖的,更别提中文版了。翻译这本书,算是复习和重新思考下Python,同时也会有少量自己的见解(C++风格注释绿色粗体),希望能坚持下去吧。我看的版本主要分为四部分:Control Structures and Functions(控制结构和函数)、Working with Data(数据和类型)、Organizing Your Code(代码组织)、General Advice(一般性建议)。每一部分里又分为不同的小章节,一共二十几个。我会按这个顺序不定期放出数目不定的章节。本人英文水平尚可,不过没有翻译经验,虽然不知道会不会有人关注这个系列,还是希望如果有看官,请轻拍指正:)
原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/
下一篇:翻译《Writing Idiomatic Python》(二):函数、异常
1. 控制结构和函数
1.1 if语句
1.1.1 通过链式比较让语句更加简明
当使用if语句时,优先使用链式比较操作,不仅会让语句更加简明,也会让执行效率更好。
不良风格:
if x <= y and y <= z:
return True
地道Python:
if x <= y <= z:
return True
// Python解释执行以上两种不同的比较方式时,其实都是先比较x<=y,如果为真,再比较y<=z。主要的区别在于,链式比较时,会先取y的值,然后复制压栈,整个过程中y的求值只执行了一次,而用and的方式时,y的求值会执行两次,也就是说,如果比较的是三个函数或者复杂的对象的话,链式比较只会求值三次,而通过and比较的方式则会求值4次。这大概就是为什么作者说执行效率会更好,但实际上如果只是简单的变量进行比较,效率未必会有提高。
1.1.2 避免将条件分支中的代码和冒号放在同一行
使用缩进来表示代码块的结构会让人更容易判断条件分支的代码结构。if,elif和else语句应该都总是独占一行,在冒号后没有代码。
不良风格:
name = 'Jeff'
address = 'New York, NY' if name: print(name)
print(address)
地道Python:
name = 'Jeff'
address = 'New York, NY' if name:
print(name)
print(address)
// 文件中的代码应该遵循这个规则,在控制台下放一行也未尝不可
1.1.3 避免在复合的if语句中重复出现同一个变量名
当想用if语句检查一个变量是否和许多值中的一个相等时,用==和or重复写许多遍是否相等的检查会显得代码很冗长。简洁的写法是判断该变量是否在一个可遍历的结构中。
不良风格:
is_generic_name = False
name = 'Tom'
if name == 'Tom' or name == 'Dick' or name == 'Harry':
is_generic_name = True
地道Python:
name = 'Tom'
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的参数是否被赋值的时候,比如:
def insert_value(value, position=None):
"""向自定义的容器中插入一个值,插入值
的位置作为可选参数,默认值为None"""
if position is not None:
...
如果使用 if position: 的话,哪里会出错呢?设想如果有人想在0位置插入一个值,那么函数会认为position这个参数没有设置,因为 if 0: 会判定为False。注意这里使用的是is not,根据PEP8,和None比较应该总是用is或者is not而不是==
总之,就让Python的“真值”代替你做比较的工作。
不良风格:
def number_of_evil_robots_attacking():
return 10 def should_raise_shields():
# 只有当一只以上的巨型机器人进攻时才打开防护罩
# 所以我只需要返回巨型机器人的数量,如果不为零会自动判断为真
return number_of_evil_robots_attacking() if should_raise_shields() == True:
raise_shields()
print('防护罩已打开')
else:
print('安全!并没有巨型机器人在进攻')
地道Python:
def number_of_evil_robots_attacking():
return 10 def should_raise_shields():
# 只有当一只以上的巨型机器人进攻时才打开防护罩
# 所以我只需要返回巨型机器人的数量,如果不为零会自动判断为真
return number_of_evil_robots_attacking() if should_raise_shields():
raise_shields()
print('防护罩已打开')
else:
print('安全!并没有巨型机器人在进攻')
1.1.5 使用if 和 else作为三元操作符的替代
和许多其他语言不同,Python没有三元操作符(比如: x ? true : false)。不过Python可以将赋值推迟到条件判断之后,所以在Python中三元操作可以用条件判断来替代。当然需要注意的是,除非是很简单的语句,否则三元操作的替代方案会让语句的可读性降低。
不良风格:
foo = True
value = 0 if foo:
value = 1 print(value)
地道Python:
foo = True value = 1 if foo else 0 print(value)
1.2 For循环
1.2.1 在循环中使用enumerate函数来创建计数或索引
在许多其他语言中,开发者习惯显式地声明一个变量用来作为循环中的计数或者相关容器的索引。例如在C++中:
for ( int i = ; i < container.size(); ++i )
{
// Do stuff
}
在Python中,内置的enumerate函数就可以很自然地处理这种需要。
不良风格:
my_container = ['Larry', 'Moe', 'Curly']
index = 0
for element in my_container:
print('{} {}'.format(index, element))
index += 1
地道Python:
my_container = ['Larry', 'Moe', 'Curly']
for index, element in enumerate(my_container):
print('{} {}'.format(index, element))
1.2.2 使用in关键字遍历可迭代结构
在没有for_each风格的语言中,开发者习惯于用索引(下标)来遍历一个容器中的元素。而在Python中,这种操作可以通过in关键字来更为优雅地实现。
不良风格:
my_list = ['Larry', 'Moe', 'Curly']
index = 0
while index < len(my_list):
print(my_list[index])
index += 1
地道Python:
my_list = ['Larry', 'Moe', 'Curly']
for element in my_list:
print(element)
1.2.3 使用else去执行一个for循环全部遍历结束后的代码
在Python的for循环中可以包含一个else分句,这是一个不多人知道的技巧。else语句块会在for循环中的迭代结束后执行,除非在迭代过程中循环因为break语句结束。利用这种写法我们可以在循环中执行条件检查。要么在要检查的条件语句为真时用break语句停止循环,要么在循环结束后进入else语句块并执行条件未被满足的情况下要执行的动作。这样做避免了在循环中单独使用一个标示变量来检查条件是否被满足。
不良风格:
for user in get_all_users():
has_malformed_email_address = False
print('检查 {}'.format(user))
for email_address in user.get_all_email_addresses():
if email_is_malformed(email_address):
has_malformed_email_address = True
print('包含恶意email地址!')
break
if not has_malformed_email_address:
print('所有email地址均有效!')
地道Python:
for user in get_all_users():
print('检查 {}'.format(user))
for email_address in user.get_all_email_addresses():
if email_is_malformed(email_address):
print('包含恶意email地址!')
break
else:
print('所有email地址均有效!')
转载请注明出处:達聞西@博客園
下一篇:翻译《Writing Idiomatic Python》(二):函数、异常
翻译《Writing Idiomatic Python》(一):if语句、for循环的更多相关文章
- 《Writing Idiomatic Python》前两部分的中文翻译
汇总了一下这本小书前两部分的内容: 翻译<Writing Idiomatic Python>(一):if语句.for循环 翻译<Writing Idiomatic Python> ...
- 翻译《Writing Idiomatic Python》(五):类、上下文管理器、生成器
原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...
- 翻译《Writing Idiomatic Python》(四):字典、集合、元组
原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...
- 翻译《Writing Idiomatic Python》(三):变量、字符串、列表
原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...
- 翻译《Writing Idiomatic Python》(二):函数、异常
原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...
- 分享书籍[writing idiomatic python ebook]
你是不是总是觉得学了python好久,蓦然回首,总是感觉写的代码不是那么有pythonic的味道.看看别人的代码(django,webpy),再看看自己的代码,觉得就是一java-python的混合体 ...
- Python 的条件语句和循环语句
一.顺序结构 顺序结构是最简单的一种程序结构,程序按照语句的书写次序自上而下顺序执行. 二.分支控制语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块 ...
- 分享书籍[writing idiomatic python ebook] 二
对多个变量设置相同的值时,用连等号一起赋值 x = 10 y = 10 z = 10 改成: x = y = z = 10 交换变量值时,可以避免定义新的临时变量 x = 10 y = 5 temp ...
- Python之条件语句以及循环
Python代码的缩进规则.具有相同缩进的代码被视为代码块 缩进请严格按照Python的习惯写法:4个空格,不要使用Tab,更不要混合Tab和空格,否则很容易造成因为缩进引起的语法错误. 注意: if ...
随机推荐
- WEB前端开发和调试的工具
前端开发在线课程: http://yun.lu/student/course/list/8 1.HBuilder:WEB开发IDE工具 hbulider,内核是eclipse,Dcloud公司出品 ...
- ahjesus根据身份证号码获取相关信息(生日,省市县,性别)
使用说明: //出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢! var idCard = new IdCard();var msg = ...
- javascript获取url信息的常见方法
先以"http://www.cnblogs.com/wuxibolgs329/p/6188619.html#flag?test=12345"为例,然后获得它的各个组成部分. 1.获 ...
- gridView使用
只读 for (int i = 0; i <9; i++) { this.gridView1.Columns[i].OptionsColumn.ReadOnly = true; } 不显示面板 ...
- 实验12:Problem C: 重载字符的加减法
Home Web Board ProblemSet Standing Status Statistics Problem C: 重载字符的加减法 Problem C: 重载字符的加减法 Time ...
- 详解Paint的setShader(Shader shader)
一.概述 setShader(Shader shader)中传入的自然是shader对象了,shader类是Android在图形变换中非常重要的一个类.Shader在三维软件中我们称之为着色器,其作用 ...
- BeanFactory not initialized or already closed - call 'refresh' before accessing beans解决办法
今天在写Spring程序时遇到了一个很常见的错误,而我以前好像一直没碰到过,今天才见到这个错误,经过研究解决了这个错误,犯这个错误真是不应该啊. log4j:WARN No appenders cou ...
- CoreAnimation-08-CATransition
概述 简介 CATransition又称转场动画,是CAAnimation的子类,可以直接使用 转场动画主要用于为图层提供移入/移出屏幕的动画效果 转场动画常见的应用是UINavigationCont ...
- This is usually caused by using Struts tags without the associated filter. Struts tags are only usable when the request has p
2014-09-16 15:47:51.590:WARN:oejs.ErrorPageErrorHandler:EXCEPTION org.apache.jasper.JasperException: ...
- maven 错误No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format
[INFO] Scanning for projects... [INFO] ------------------------------------------------------------- ...