可迭代对象和迭代器
python 从可迭代对象获得迭代器
迭代器实现了 __next__
__iter__
两个方法
没有实现 __iter__
无法用 for 迭代
迭代器是这样一个对象,实现了无参数的 next 方法,返回序列中的下一个元素;如果没有元素了,那么抛出 StopIteration 异常。
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 __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text)
def __iter__(self):
# 实现了该方法就是可迭代对象
# 可迭代对象,返回迭代器,每次实例化后返回新的迭代器
# 调用 iter(x) 判断x 是否是可迭代对象
return SentenceIterator(self.words)
class SentenceIterator:
# 迭代器
def __init__(self, words):
self.words = words
self.index = 0
def __next__(self):
# 返回单个元素
# 迭代器必须实现的方法
try:
word = self.words[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return word
def __iter__(self):
# 迭代器必须实现的方法
# 返回自身
return self
迭代器与可迭代对象总结
- 可迭代对象返回迭代器(iter)
- 可迭代对象无法通过next 方法,获取下个数据
- 迭代器无法获取集合中的某个值,只能依次访问
- 不能回退,支持对聚合对象的多种遍历
- 要知道,可迭代的对象有个 iter 方法,每次都实例化一个新的迭代器;而迭代器要实现 next 方法,返回单个元素,此外还要实现 iter 方法,返回迭代器本身。
iter 鲜为人知的用法
iter(func, i) i 为一种标识,当到i,抛出异常 ```python with open(path, ‘r’) as f: for line in iter(f.readline, ‘\n’):process_line(line)
迭代读取文件,直到遇到空行或者文件末尾停止
<a name="yfEs7"></a>
### 生成器
只要定义了yield 的函数就是一个生成器函数<br />惰性获取数据
<a name="DJZJg"></a>
#### 2.1生成器应用,读取大数据文件
```python
# 正常csv文件可能是单个分隔符(,),现在分隔符是两个字符(||),Python无法处理这种两个字符的分隔符
# 需要自定义读取一行数据,split(分隔符), 返回格式化数据
def read_file_head(file, delimiter=None):
# 读取文件头 head
# 自定义分割符,(,;||等)
with open(file) as f:
one_line = f.readline()
return one_line.strip().split(delimiter)
def delimited(file, delimiter='\n', bufsize=4096):
# 一次读取文件4096字节数据,如果出现一行结尾,则yield 这行数据
buf = ''
while True:
newbuf = file.read(bufsize)
if not newbuf:
yield buf
return
buf += newbuf
lines = buf.split(delimiter)
for line in lines[:-1]:
yield line
buf = lines[-1]
def read_file_by_line(file, lf, length, flag):
"""
file 文件名
lf 文件一行末尾数据格式(换行符)
length 默认一行数据长度
flag 一行字段与字段之间分隔符
"""
head = read_file_head(file, flag)
with open(file, encoding='utf-8') as f:
next(f) # 迭代第一行,这是文件头
lines = delimited(f, lf, 4096)
for line in lines:
res = dict(zip(head, line.split(flag)))
if len(res) == length:
yield res