可迭代对象、迭代器和生成器
Python充分利用多核性能的阻碍在于全局解释器锁(GIL)
GIL确保python进程一次只能执行一条指令,无论当前有多少个核心。
解决方法:标准库:multiprocessing、numerpr
什么是RAM?
更快的读写速度且在随机访问时性能良好
L1/L2缓存
极快的读写速度,进入CPU的数据必须进过这里
迭代器模式
迭代器模式(Iterator patter): 按需一次获取一个数据项目
所有生成器都是迭代器,因为生成器完全实现了迭代器接口
迭代器用于从集合中取出元素,生成器用于"凭空生成元素"
import re
import reprlib
RE_WORD = re.compile('w+')
class Sentence:
def __init__(self, text):
# 初始化参数
self.text = text
self.words = RE_WORD.findall(text)
def __getitem__(self, index):
# 可通过索引获取对应的value
return self.words[index]
def __len__(self)
# 句子长度
return len(self.words)
def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text)
为什么序列可以迭代?原因是什么?
解释器需要迭代对象 x 时,会自动调用 iter(x)。
内置iter函数的作用?
- 检查对象是否实现了__iter__方法,如果实现了就调用它,获取一个迭代器
- 检查没有实现__iter__方法,但是实现了__geritem__方法,Python会创建一个迭代器,尝试按顺序(从索引0开始)获取元素
- 如果尝试失败,Python 抛出 TypeError 异常,通常会提示“C object is not iterable”(C
- 对象不可迭代),其中 C 是目标对象所属的类。
任何序列都可迭代的原因是,都实现了__getitem__方法,其实,标准的序列也都实现了__iter__方法
鸭子类型:即实现了__iter__方法,还要实现__getitem__方法,且__getitem__方法的参数是从0开始的整数(int),这样才认为对象是可迭代的。
如何检查一个对象能否迭代?
最准确的方法是:调用iter(x)函数,如果不可迭代,在处理TypeError异常,这比isinstance(x, abc.Iterable)更准确,因为iter(x)函数会考虑到遗留__getitem__方法,而abc.Iterable类则不考虑
可迭代的对象与迭代器的对比
可迭代的对象
- 使用iter内置函数可以获取迭代器的对象。
- 如果对象实现了能返回迭代器的__iter__方法,那对象就是可迭代的.
- 序列都可以迭代;实现了__getitem__方法,而且其参数是从0开始的索引,这种对象也可以迭代。
可迭代对象和迭代器的关系:python从可迭代的对象中获取迭代器
s = 'ABC'
it = iter(s)
while True:
try:
print(next(it)) # 不断在迭代器上调用next函数,获取下一个字符
except StopIteration:
del it # 释放对it的引用,即废弃迭代器对象
break
标准的迭代器接口有两个方法
__next__: 返回下一个可用的元素,如果没有元素了,抛出StopIteration异常
__iter__:返回self,以便在应该使用可迭代对象的地方使用迭代器
Iterator抽象基类实现__iter__方法的方式是返回实例本身(return self)。这样,在需要可迭代对象的地方可以使用迭代器。
为什么想再次迭代,需要重新构建迭代器?
因为迭代器只需__next__和__iter__两个方法,所以除了调用next()方法,以及捕获StopIteration异常之外,没有办法检查是否还有遗留的元素,此外,也没有办法还原迭代器,如果想再次迭代,那就要调用iter(),传入之前构建迭代器的可迭代对象。
传入迭代器本身没用,因为前面说过 Iterator.iter 方法的实现方式是返回实例本身,所以传入迭代器无法还原已经耗尽的迭代器。
迭代器
迭代器是这样的对象:实现了无参数的 next 方法,返回序列中的下一个元素;如 果没有元素了,那么抛出 StopIteration 异常。Python 中的迭代器还实现了 iter 方 法,因此迭代器也可以迭代。