Python中迭代器与生成器怎么使用
一、迭代器(foreach)
1、可迭代的对象
内置有__iter__方法的都叫可迭代的对象。
Python内置str、list、tuple、dict、set、file都是可迭代对象。
x = 1.__iter__ # SyntaxError: invalid syntax# 以下都是可迭代的对象name = 'nick'.__iter__print(type(name)) # 'method-wrapper'>
2、迭代器对象
执行可迭代对象的__iter__方法,拿到的返回值就是迭代器对象。
只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的,只能使用迭代器对象。
内置有__iter__方法,执行该方法会拿到迭代器本身。
立即学习“Python免费学习笔记(深入)”;
内置__next__方法,执行该方法会拿到迭代器对象中的一个值。
s = 'hello'iter_s = s.__iter__()print(type(iter_s)) # 'str_iterator'> iter_s为迭代器对象while True: try: print(iter_s.__next__()) except StopIteration: break#hello
3、迭代器有两个基本的方法:iter() 和 next()。
s = 'hello'iter_s = iter(s) # 创建迭代器对象print(type(iter_s)) # iter_s为迭代器对象while True: try: print(next(iter_s)) # 输出迭代器的下一个元素 except StopIteration: break# hello
4、for迭代器循环
可迭代对象可以直接使用常规for语句进行遍历
for循环称为迭代器循环,in后必须是可迭代的对象。
#strname = 'nick' for x in name: print(x)#listfor x in [None, 3, 4.5, "foo", lambda: "moo", object, object()]: print("{0} ({1})".format(x, type(x)))#dictd = { '1': 'tasty', '2': 'the best', '3 sprouts': 'evil', '4': 'pretty good'}for sKey in d: print("{0} are {1}".format(sKey, d[sKey]))#filef = open('32.txt', 'r', encoding='utf-8')for x in f: print(x)f.close()
5、实现迭代器(__next__和__iter__)
在类中实现 __iter__() 和 __next__() 两个方法后,即可使其作为迭代器来使用。
__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
__next__() 方法会返回下一个迭代器对象。
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
创建一个返回数字的迭代器,初始值为 1,逐步递增 1,在 20 次迭代后停止执行:
class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): if self.a <h4>1、模拟range</h4><pre class="brush:py;">class Range: def __init__(self, n, stop, step): self.n = n self.stop = stop self.step = step def __next__(self): if self.n >= self.stop: raise StopIteration x = self.n self.n += self.step return x def __iter__(self): return selffor i in Range(1, 7, 3): print(i)#1#4
2、斐波那契数列
class Fib: def __init__(self): self._a = 0 self._b = 1 def __iter__(self): return self def __next__(self): self._a, self._b = self._b, self._a + self._b return self._af1 = Fib()for i in f1: if i > 100: break print('%s ' % i, end='')# 1 1 2 3 5 8 13 21 34 55 89
二、生成器
1、yield
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
生成器是一种特殊的函数,它返回一个迭代器,仅可用于迭代操作。换言之,生成器就是一种迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象。
yield后面可以加多个数值(可以是任意类型),但返回的值是元组类型的。
提供一种自定义迭代器的方式
yield可以暂停住函数,并提供当前的返回值
import sysdef fibonacci(n): # 函数 - 斐波那契 a, b, counter = 0, 1, 0 while True: if counter > n: return yield a a, b = b, a + b counter += 1f = fibonacci(10) #f 是一个生成器print(type(f)) # 'generator'>while True: try: print(next(f), end=" ") except StopIteration: sys.exit()
yield和return:
相同点:两者都是在函数内部使用,都可以返回值,并且返回值没有类型和个数的限制
不同点:return只能返回一次值;yield可以返回多次值
2、自定义range()方法
def my_range(start, stop, step=1): while start <p>复杂版本:</p><pre class="brush:py;">def range(*args, **kwargs): if not kwargs: if len(args) == 1: count = 0 while count <h4>3、生成器表达式(i.for .in)</h4><p>把列表推导式的[]换成()就是生成器表达式 。</p><p>优点:比起列表推导式,可以省内存,一次只产生一个值在内存中</p><pre class="brush:py;">t = (i for i in range(10))print(t) # <generator>print(next(t)) # 0print(next(t)) # 1</generator>
举例:
with open('32.txt', 'r', encoding='utf8') as f: nums = [len(line) for line in f] # 列表推导式相当于直接给你一筐蛋print(max(nums)) # 2with open('32.txt', 'r', encoding='utf8') as f: nums = (len(line) for line in f) # 生成器表达式相当于给你一只老母鸡。print(max(nums)) # ValueError: I/O operation on closed file.