1. 用列表推导取代 map 与 filter
因为不需要写 lambda 表达式。
可以很容易地跳过原列表中的某些数据。
# 列表推导
l = [i for i in range(5)]
# [0, 1, 2, 3, 4]
print(l)
# 字典推导
d = {i: i ** 2 for i in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
print(d)
2. 控制推导逻辑的子表达式不要超过两个
推导的时候,可以使用多个 if 条件。如果这些 if 条件出现在同一层循环内,那么它们之间默认是 and 关系,也就是必须同时成立。
在推导时,每一层的 for 子表达式都可以带有 if 条件
在表示推导逻辑时,最多只应该写两个子表达式(例如两个 if 条件、两个 for 循环,或者一个 if 条件与一个 for 循环)否则,应该采用 if 和 for 语句来实现,或编写辅助函数。
3. 用赋值表达式消除推导中的重复代码
编写推导式与生成器表达式时,可以在描述条件的那一部分通过赋值表达式定义变量,并在其他部分复用该变量,可使程序简单易读。
建议赋值表达式只出现在推导逻辑的条件之中。
4. 不要让函数直接返回列表,应该让它逐个生成列表里的值
使用生成器可以降低对内存的消耗。
生成器函数所返回的迭代器是有状态的,无法重复调用。
5. 谨慎地迭代函数所收到的参数
函数和方法收到的参数如果要迭代许多次,那就要小心,如果这些参数是迭代器的话,就可能得不到预期的值。
Python 的迭代器协议确定了容器与迭代器应该怎样跟内置的 iter 及 next 函数、for 循环及相关的表达式交互:
- Python 执行 for x in foo 这样的语句时,实际上会调用 iter(foo),也就是把 foo 传给内置的 iter 函数。
- iter 函数会触发名为
foo.__iter__
的特殊方法,该方法必须返回迭代器对象(这个迭代器对象本身要实现__next__
特殊方法) - Python 会用迭代器对象反复调用内置的 next 函数,直到数据耗尽为止
要想让自定义的容器类型可以迭代,只需要把__iter__
方法实现为生成器即可。
可以把值传给 iter 函数,检测它返回的是不是那个值本身。如果是,就说明这是个普通的迭代器,而不是一个可以迭代的容器。另外,也可以用内置的 isinstance 函数判断该值是不是 collections.abc.Iterator 类的实例。
6. 考虑用生成器表达式改写数据量较大的列表推导
要想处理大规模的数据,可以使用生成器表达式(generator expression)来做,它扩展了列表推导式与生成器机制。
生成器表达式可以组合起来,编写一条新的生成器表达式(连锁反应):
l = [1, 2, 3, 4, 5]
it = (i for i in l)
it2 = ((i + 1, i ** 2) for i in it)
print(next(it)) # 1
print(next(it2)) # (3, 4)
print(next(it)) # 3
print(next(it)) # 4
7. 通过 yield from 把多个生成器连起来用
用yeild from
优化for-yeild
结构:
- 会先从嵌套进去的小生成器里面取值,如果该生成器已经用完,那么程序的控制流程就会回到 yield from 所在的这个函数之中,然后它有可能进入下一套 yield from 逻辑
更快,层次结构更分明。
8. 不要用 send 给生成器注入数据
替代方案:通过把迭代器传给函数,通过 next 函数推进该迭代器返回需要用到的参数
优点:
- 迭代器可以来自任何地方,完全可以是动态的
缺点:
- 必须假设输入的生成器绝对能够保证线程安全
9. 不要通过 throw 变换生成器的状态
解决办法:定义一个有状态的闭包文章来源:https://www.toymoban.com/news/detail-654828.html
10. 考虑用 itertools 拼接迭代器与生成器
如果要实现比较难写的迭代逻辑,那么应该先查看 itertools 的文档(在 Python 解释器界面输入 help(itertools)文章来源地址https://www.toymoban.com/news/detail-654828.html
连接多个迭代器
过滤迭代器中的元素
到了这里,关于【Effective Python】读书笔记-04推导与生成的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!