python代码整洁之道
1、真值判断
检查某个对象是否为真值时,还显示的与 True 和 False 做比较,这就显得多此一举
- unpythonic
if attr == True:
do_something()
if len(values) != 0: # 判断列表是否为空
do_something()
- pythonic
if attr:
do_something()
if values:
do_something()
真假值对照表:
类型 | False | True |
---|---|---|
布尔 | False(与0等价) | True(与1等价) |
数值 | 0, 0.0 | 非零的数值 |
字符串 | '', ""(空字符串) | 非空字符串 |
容器 | [], (), {}, set() | 至少有一个元素的容器对象 |
None | None | 非None对象 |
2、预设字典默认值
通过 key 分组的时候,不得不每次检查 key 是否已经存在于字典中。
- unpythonic
data = [('foo', 10), ('bar', 20), ('foo', 39), ('bar', 49)]
groups = {}
for (key, value) in data:
if key in groups:
groups[key].append(value)
else:
groups[key] = [value]
- pythonic
# 第一种方式
groups = {}
for (key, value) in data:
groups.setdefault(key, []).append(value)
# 第二种方式
from collections import defaultdict
groups = defaultdict(list)
for (key, value) in data:
groups[key].append(value)
结果:
{'foo': [10, 39], 'bar': [20, 49]}
setdefault:
Python 字典 setdefault() 方法和 get()方法 类似, 如果键不存在于字典中,将会添加键并将值设为默认值。
defaultdict:
defaultdict是Python内建dict类的一个子类,第一个参数为default_factory属性提供初始值,默认为None。它覆盖一个方法并添加一个可写实例变量。它的其他功能与dict相同,但会为一个不存在的键提供默认值,从而避免KeyError异常。
# 统计某个单词出现的次数, 并选出排名前三的单词
from collections import defaultdict
words = ('python', 'python', 'hello', 'world', 'world', 'world', 'man')
counts = defaultdict(lambda: 0)
for word in words:
counts[word] += 1
sorted_words = sorted(counts.items(), key=lambda x: x[1], reverse=True)
print(sorted_words[:3])
3、列表推导式(生成式)
构建列表对象一般使用下面这种方式,可读性非常差
- unpythonic
test_list = []
for i in range(10):
test_list.append(i*2)
- pythonic
test_list = [i*2 for i in range(10)]
比如:找出员工工资低于当地最低工资标准(<$9)的公司名称
- unpythonic
companies = {
'CoolCompany': {'Alice': 33, 'Bob': 28, 'Frank': 29},
'CheapCompany': {'Ann': 4, 'Lee': 9, 'Chrisi': 7},
'SosoCompany': {'Esther': 38, 'Cole': 8, 'Paris': 18}
}
illege_companies1 = []
for company in companies:
for salary in companies[company].values():
if salary < 9:
illege_companies1.append(company)
print(set(illege_companies1))
- pythonic
companies = {
'CoolCompany': {'Alice': 33, 'Bob': 28, 'Frank': 29},
'CheapCompany': {'Ann': 4, 'Lee': 9, 'Chrisi': 7},
'SosoCompany': {'Esther': 38, 'Cole': 8, 'Paris': 18}
}
illege_companies2 = [company for company in companies if any(salary < 9 for salary in companies[company].values())]
print(illege_companies2)
# python的any()函数。它接受一个可迭代对象,比如列表,如果这个可迭代对象中至少有一个的真值判断为True,它就会返回True。例如,表达式any([True,False,False,False])的结果为True,而any([2<1,3+2>5+5,3-2<0,0])的结果为False。
比如:把字段名称添加到员工数据里,由此创建出一个由字典构成的列表,每个字典中将字段名分配给对应的值
column_names = ['name', 'salary', 'job']
db_rows = [('Alice', 180000, 'data scientist'), ('Bob', 99000, 'mid-level manager'), ('Frank', 87000, 'CEO')]
employee_info = [dict(zip(column_names, db)) for db in db_rows]
# zip压缩后是元组,为不能hash的数据类型,也就是不可变的类型,所以不能用字典解析式,因为其不可hash
print(employee_info)
4、切片赋值
- pythonic
visitors = ['Firefox', 'corrupted', 'Chrome', 'corrupted',
'Safari', 'corrupted', 'Safari', 'corrupted',
'Chrome', 'corrupted', 'Firefox', 'corrupted']
# 想要得到的结果是这样,也就是偶数位的都是需要被替换的前一位的值
new_visitors = ['Firefox', 'Firefox', 'Chrome', 'Chrome',
'Safari', 'Safari', 'Safari', 'Safari',
'Chrome', 'Chrome', 'Firefox', 'Firefox']
visitors[1::2] = visitors[::2]
print(visitors)
5、匿名函数
匿名函数 lambda 和常规函数一样,返回的都是一个函数对象。
匿名函数最难理解的地方就是要传入的参数是一个可迭代的对象,lambda 内部会调用可迭代对象的 next 方法取值当作参数传入 lambda 函数冒号前面的值,然后把表达式计算的结果进行返回。
- unpythonic
# 计算平方
def square(x):
return x**2
squared = map(square, [1, 2, 3, 4, 5])
# 常规函数 def 必须通过其函数名被调用,因此必须首先被定义,另外,注意map调用的是函数名称
- pythonic
squared = map(lambda x: x**2, [1, 2, 3, 4, 5])
- unpythonic
# 过滤操作
a = [3, 4, 5]
b = []
for i in a:
if i > 4:
b.append(i)
- pythonic
b = filter(lambda x: x > 4, a)
#filter函数,它和 map 函数类似,function 同样表示一个函数对象。filter() 函数表示对 iterable 中的每个元素,都使用 function 判断,并返回 True 或者 False,最后将返回 True 的元素组成一个新的可遍历的集合。
# 累积操作
from functools import reduce
l = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, l) # 1*2*3*4*5 = 120
# educe(function, iterable) 函数,它通常用来对一个集合做一些累积操作。function 同样是一个函数对象,规定它有两个参数,表示对 iterable 中的每个元素以及上一次调用后的结果,运用 function 进行计算,所以最后返回的是一个单独的数值。
6、访问字典元素
- unpythonic
#如果字段中存在某键时,打印其值,否则给其赋上默认值
d = {'hello': 'world'}
if d.has_key('hello'):
print d['hello'] # prints 'world'
else:
print 'default_value'
- pythonic
d = {'hello': 'world'}
print d.get('hello', 'default_value')
# prints 'world'
print d.get('thingy', 'default_value')
# 不存在‘thingy’键,于是赋值为'default_value'
# Or:
if 'hello' in d:
print d['hello']