由于自己的神操作,导致自己写了很久的2篇笔记被删了,现在写第3篇!
写在前面,当涉及迭代操作时,优先查看itertools库!
1.反向迭代
在python中已经有了内置的reversed函数实现反向迭代,但是只有对象实现了__reversed__方法或者可以确定待处理的对象的大小才可使用。如果对象的数量大,还会带来性能问题。通过自定义__reversed__对象可以实现反向迭代。
class Countdown(object):
def __init__(self, start):
self.start = start
def __iter__(self):
# 正向迭代
n = self.start
while n > 0:
yield n
n -= 1
def __reversed__(self):
# 反向迭代
n = 1
while n <= self.start:
yield n
n += 1
if __name__ == '__main__':
c = Countdown(5)
for x in c.__iter__():
print(x) # 5 4 3 2 1
for i in c.__reversed__():
print(i) # 1 2 3 4 5
2.对迭代器作切片操作
对迭代器或生成器作切片操作时,使用itertools.islice函数。
def count(n):
while True:
yield n
n += 1
if __name__ == '__main__':
c = count(0)
#如果你打算c[10:20],别想了,c是生成器
from collections import Iterator
it = itertools.islice(c, 10, 20)
# 如果将20替换为None,将表示除前10个元素之外的所有元素。
print(it) # <itertools.islice object at 0x00000194FDB7B2C8>
print(isinstance(it, Iterator)) # True,它是一个迭代器
for i in itertools.islice(c, 10, 20):
print(i) # 10 11 ... 19 20
注意:之所以可以进行切片,是因为它将之前的元素都丢弃了,如果你需要切片处之前的元素,应该提前保存元素。
3.跳过可迭代元素的前一部分元素
如果你进行迭代操作,但不想要前面的元素,可以使用itertools.dropwhile()函数,参数:1个函数,1个可迭代对象,return的迭代器会丢弃序列中前几个元素。
如果你打开一个文件,文件中包含注释:
# 445566677
# 88866699
# /+--52566
# dsd
......
你不需要注释,可以这样写:
>>>from itertools import dropwhile
>>>with open('/etc/passwd') as f:
for line in dropwhile(lambda line: line.startswith('#')):
print(line)
>>> # 一直丢弃,直到没有#
使用dropwhile函数的优势是,它只会丢弃满足条件的元素,直到有某个元素不满足条件为止,对后面满足的元素无影响。
4.迭代所有可能的组合
比如有一个数组a,a=[1,2,3],你希望获取该数组的所有组合,可以使用itertools库中的permutations()方法,该方法接收一个元素集合,将其中所有的元素重排列为所有可能的情况。(返回元组,结果为数组a中的元素的所有组合,但是没有相同项)
from itertools import permutations
a = [1, 2, 3]
for i in permutations(a):
print(i)
results:
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)
permutations还接收一个参数,该参数可以限定返回的排列长度。
for i in permutations(a, 2):
print(i)
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
(3, 2)
使用itertools.combinations()方法可以产生输入序列中所有元素的全部组合形式。
from itertools import combinations
a = [1, 2, 3]
for i in combinations(a, 2):
print(i)
当参数为2时:(1, 2)
(1, 3)
(2, 3)
当参数为3时:(1, 2, 3)
该方法返回的内容,不考虑元素的顺序,即(1,2)与(2,1)内容相同。
若需要返回所有的可能性可以使用itertools.combinations_with_replacement方法。
for i in combinations_with_replacement(a, 3):
print(i)
结果:(1, 1, 1)
(1, 1, 2)
(1, 1, 3)
(1, 2, 2)
(1, 2, 3)
(1, 3, 3)
(2, 2, 2)
(2, 2, 3)
(2, 3, 3)
(3, 3, 3)
5.以索引-值对的形式迭代序列
迭代一个序列但是希望记录当前元素的索引
使用enumerate()(枚举),enumerate()还接收一个参数,用于指定起始索引。
a = [a, b, c]
for i in enumerate(a):
print(i)
(0, 'a')
(1, 'b')
(2, 'c')
当指定另一个参数为1时,
(1, 'a')
(2, 'b')
(3, 'c')
*当在元组序列上使用enumerate时,注意元组不可以展开,否则报错。
a = [(1, 2), (3, 4), (4, 5)]
for i in enumerate(a):
print(i)
(0, (1, 2))
(1, (3, 4))
(2, (4, 5))
a = [(1, 2), (3, 4), (4, 5)]
for i, (k, v) in enumerate(a):
print(i, k, v)
0 1 2
1 3 4
2 4 5
若for i, k, v in enumerate(a):
#ValueError: not enough values to unpack (expected 3, got 2)
6.同时迭代多个序列
使用zip可以迭代多个序列,zip对象返回的是一个迭代器。
a = ['a', 'b', 'c']
b = [1, 2, 3]
for i in zip(a, b):
print(i)
('a', 1)
('b', 2)
('c', 3)
当a的元素大于b时,以b的数量为主。
a = ['a', 'b', 'c', 'd']
b = [1, 2, 3]
for i in zip(a, b):
print(i)
# 依然打印了3个
('a', 1)
('b', 2)
('c', 3)
如果你不希望仅返回少数的数据可以使用itertools.zip_longest()
from itertools import zip_longest
a = ['a', 'b', 'c', 'd']
b = [1, 2, 3]
for i in zip_longest(a, b):
print(i)
# results:
('a', 1)
('b', 2)
('c', 3)
('d', None)
当超过最小长度后,默认置为None。
zip可以比较方便的生成字典。
a = ['a', 'b', 'c']
b = [1, 2, 3]
print(dict(zip(a, b)))
# {'a': 1, 'b': 2, 'c': 3}
7.在不同的容器中迭代
需要对许多对象执行相同操作,但是这些对象包含在不同容器中,且希望避免写过多的循环。可以使用itertools.chain()简化操作,见下面例子。
from itertools import chain
a = ['a', 'b', 'c', 'd']
b = [1, 2, 3]
for i in chain(a, b):
print(i)
# a b c d 1 2 3
a = ['a', 'b', 'c', 'd']
b = [1, 2, 3]
c = ('f', 'g', 'h') # 支持不同的类型,传入多个序列
for i in chain(a, b, c):
print(i)
# a b c d 1 2 3 f g h
8.合并多个有序序列,再对整个有序序列进行迭代
我们有一组有序序列,相对它们合并后的有序序列进行迭代。
可以使用heapq.merge()函数。
import heapq
a = [9, 8, 7]
b = [1, 2, 3]
c = ('f', 'g', 'h')
for i in heapq.merge(a, b):
print(i)
1
2
3
9
8
7
heapq.merge不会对提供的序列做一次性读取,因此,该函数可以处理非常长的序列,而且开销小。下方例子告诉可以合并两个有序的文件:
# 第一次知道with可以这样写!!!
with open('sorted_file', 'rt') as file1,\
open('sorted_file_2', 'rt') as file2,\
open('merged_file', 'wt') as outf:
for line in heapq.merge(file1, file2):
outf.write(line)
**重点强调:
heapq.merge要求suo'y所有输入的序列都是有序的,它不会将所有数据读取到堆中,或者预先做任何的排序操作,它也不会对输入做任何验证,以检查它们是否满足有序的要求。相反,它只是简单的检查每个输入序列中的第一个元素,将最小的那个发送出去。然后再从之前选择的序列中读取一个新的元素,重复该步骤,直到没有数据取完。
9.使用迭代器取代while循环
这是一个神奇的操作!
伪代码1:
涉及I/O操作:
CHUNKSIZE = 8192
def reader(s):
with True:
data = s.recv(CHUNKSIZE) # recv指定缓冲区的大小
if data == b'':
break
process_data(data)
使用iter()替换:
CHUNKSIZE = 8192
def reader(s):
for chunk in iter(lambda: s.recv(CHUNKSIZE), b''):
process_data(chunk)
内置函数iter()有一个特性,它可以选择性接受一个无参的可调用对象以及一个 结束标志 作输出,当以该种方式使用时,iter()会创建一个迭代器,然后重复调用,直到遇到结束标志,停止。
评论列表
已有0条评论