5.1 条件语句
在使用条件语句时,很多人喜欢省略判断条件:
if s: # s is a string
...
if l: # l is a list
...
if i: # i is an int
...
...
不过,在实际代码写代码时,还是不鼓励省略判断条件的写法(除了Boolean类型),条件判断最好是显性的。比如,在判断整型数是否为0时,最好写出判断的条件:
if i != 0:
...
而不是只写出变量名:
if i:
...
5.2 循环语句
通过循环语句可以遍历可迭代(iterable)的数据结构。
对于字典,只有键是可迭代的。如果要遍历值,则需要用到字典的内置函数dict.values();遍历键值对则需用到dict.items()
d = {'name': 'jason', 'dob': '2000-01-01', 'gender': 'male'}
for k in d: # 遍历字典的键
print(k)
name
dob
gender
for v in d.values(): # 遍历字典的值
print(v)
jason
2000-01-01
male
for k, v in d.items(): # 遍历字典的键值对
print('key: {}, value: {}'.format(k, v))
key: name, value: jason
key: dob, value: 2000-01-01
key: gender, value: male
善用enumerate(<iterable>)函数
善用continue
在循环中,适当使用continue能使代码更简洁。
比如,给定两个字典,分别是产品名称到价格的映射,和产品名称到颜色列表的映射。我们要找出价格小于 1000,并且颜色不是红色的所有产品名称和颜色的组合。如果不用 continue,代码应该是下面这样的:
# name_price: 产品名称 (str) 到价格 (int) 的映射字典
# name_color: 产品名字 (str) 到颜色 (list of str) 的映射字典
for name, price in name_price.items():
if price < 1000:
if name in name_color:
for color in name_color[name]:
if color != 'red':
print('name: {}, color: {}'.format(name, color))
else:
print('name: {}, color: {}'.format(name, 'None'))
使用了continue之后,代码更加清晰:
# name_price: 产品名称 (str) 到价格 (int) 的映射字典
# name_color: 产品名字 (str) 到颜色 (list of str) 的映射字典
for name, price in name_price.items():
if price >= 1000:
continue
if name not in name_color:
print('name: {}, color: {}'.format(name, 'None'))
continue
for color in name_color[name]:
if color == 'red':
continue
print('name: {}, color: {}'.format(name, color))
第一种写法有5层for或if的嵌套,第二种写法只有3层嵌套。多重嵌套会使得代码冗余、难读,也不利于后续的调试、修改。因此要尽量避免多层嵌套。
5.3 效率比较
对于遍历,有以下两种写法:
i = 0
while i < 1000000:
i += 1
for i in range(0, 1000000):
pass
第二种写法的效率更快,原因是:range()是C函数写的可以直接调用;而i+1操作得通过python解释器间接调用底层的C语言,而且还涉及到了对象的创建和删除(因为i是整型,是immutable,相当于i = new int(i+1))
5.4 循环进阶:一行代码写多重循环
1.判断条件中有else
expression1 if condition else expression2 for item in iterable
等价于:
for item in iterable:
if condition:
expression1
else:
expression2
- 判断条件中没有else
expression for item in iterable if condition
示例1:
对于函数y = 2*|x| + 5,给定集合x的数据点,需要计算出y的数据集合,则可使用下面一行语句完成:
y = [value*2 + 5 if value > 0 else -value * 2 + 5 for value in x]
示例2:
对于一个字符串,去掉空格以及字母少于3的单词:
方法1:
import re
words = ' Today, is , Sunday,I think you could be happy.'
wordlist = re.findall(r'\w+', words)
result = [x for x in wordlist if len(x)>=3]
=====================================================
['Today', 'Sunday', 'think', 'you', 'could', 'happy']
方法2:
words = ' Today, is , Sunday,I ,think, you ,could, be, happy'
result = [word.strip() for word in words.split(',') if len(word.strip())>=3]
===================================
['Today', 'Sunday', 'think', 'you', 'could', 'happy']
- 双重循环写一行
[(xx, yy) for xx in x for yy in y if xx != yy]
等价于:
l = []
for xx in x:
for yy in y:
if xx != yy:
l.append((xx, yy))
熟练之后,这种写法会非常方便。
5.5 总结
5.6 思考题
给定下面两个列表 attributes 和 values,要求针对 values 中每一组子列表 value,输出其和 attributes中的键对应后的字典,最后返回字典组成的列表。
attributes = ['name', 'dob', 'gender']
values = [['jason', '2000-01-01', 'male'],
['mike', '1999-01-01', 'male'],
['nancy', '2001-02-01', 'female']
]
# expected outout:
[{'name': 'jason', 'dob': '2000-01-01', 'gender': 'male'},
{'name': 'mike', 'dob': '1999-01-01', 'gender': 'male'},
{'name': 'nancy', 'dob': '2001-02-01', 'gender': 'female'}]
多行代码
attributes = ['name', 'dob', 'gender']
values = [['jason', '2000-01-01', 'male'],
['mike', '1999-01-01', 'male'],
['nancy', '2001-02-01', 'female']
]
result = []
for value in values:
person = {}
for index,attr in enumerate(attributes):
person[attr] = value[index]
result.append(person)
一行代码
注意到attributes数组的元素个数和values的元素value的元素个数相同,则可使用同一个索引下标:
result = [{attributes[index]:value[index] for index in range(len(attributes))} for value in values]
注意到attributes数组的元素个数和values的元素value的元素个数相同,则可利用zip()函数直接打包
result = [dict(zip(attributes,value)) for value in values]