迭代器
- 迭代器不能回退,只能如过河卒子一样,不断前进
- 迭代器也不适合在多线程中对可变集合使用
- 特性:一个对象,只能循环一次,若再读就没有任何结果了(游标已经移动到了最后)。
仿写range() 的对象
class MyRange(object):
def __init__(self,n):
self.i = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.i < self.n:
i = self.i
self.i += 1
return i
else:
raise StopIteration()
if __name__ == "__main__":
x = MyRange(7)
print(x.__next__())
print(x.__next__())
for i in x:
print (i)
0
1
2
3
4
5
6
分析:
-
__iter__()
是类的核心,返回了迭代器本身,实现了__iter__()
方法的对象,以为着其可以迭代 - 含有
__next__()
的对象就是迭代器,并且在这个方法中,在没有元素的时候发起StopIteration()
异常
class Fibs:
def __init__(self,max):
self.max = max
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
fib = self.a
if fib > self.max:
raise StopIteration()
self.a, self.b = self.b , self.a + self.b
return fib
fib = Fibs(1000)
print(list(fib))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
斐波那契数列 中大于1000的最小数
class Fibs_max1000:
def __init__(self,min):
self.min = min
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
fib = self.a
if self.a > self.min:
raise StopIteration()
self.a, self.b = self.b , self.a + self.b
return self.a
fib = Fibs_max1000(1000)
print(list(fib))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]
Python 2 中的 range() 和 xrange()
- 都是内建函数
- range() 返回的是一个列表
- xrange()返回的是一个对象,类似range(),但不是列表
- 循环的时候 xrange()比range()稍快,并有更高的内存效率
- xrange()是可以迭代的,它返回的是一个可迭代对象。
- range()是得到的列表会一次性被读入内存,而xrange()返回的对象,则需要一个数值才能返回一个数值
Python3 中只有range() ,和Python2 中的xrange()是一样的可以迭代的。
range(10000)
range(0, 10000)
生成器(generator)
- 生成器必须是可迭代的,但又不完全等同于迭代器
- 把解析中的‘【】’ 换成‘()’ -> 生成器解析式/生成器推导式/生成器表达式
- 用途:
- 代替列表解析当针对大数据的时候,Python处理列表时,将全部数据读入到内存中,而迭代器的优势在于可以只将所需的读入内存。因此生成器解析式比列表解析式少占内存。
- yield :
- 含有yield关键字的函数是一个生成器类型对象,这个生成器对象是可迭代的。
- 调用的时候返回相应的值。
- 不用使用
__iter__()
和__next__()
,只要使用yield 就可以使其具备迭代器的功能特性
- 一个函数中包含yield语句,它就是生成器,也是迭代器。这种方式比前面写迭代器要简便很多,但不是意味着就可以抛弃迭代器,至于用迭代器和生成器就要视具体情况而定了。
#生成器
my_generator = (x*x for x in range(4))
for i in my_generator:
print(i)
0
1
4
9
for i in my_generator:
print(i)
游标已经到最末尾,所以没有数据了,只能前进不能倒退。
#列表
my_list = [x*x for x in range(4)]
for i in my_list:
print(i)
0
1
4
9
for i in my_list:
print(i)
0
1
4
9
用途示例:
#生成器
sum(x*x for x in range(10))
285
#列表
sum([x*x for x in range(10)])
285
yield
def g():
yield 0
yield 1
yield 2
yield 3
ge = g() #返回生成器
type(ge)
generator
ge.__next__() #开始执行,遇到第一个yield将值返回,并暂停执行(挂起)
0
ge.__next__() #从上次暂停位置开始,向下执行,遇到yield,将值返回,又挂起
1
ge.__next__() #重复上一步
2
ge.__next__() #重复上一步
3
ge.__next__() #从上面挂起的位置开始,但是后美女没有可执行的了,于是 __next__异常
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-59-fcae21b194e6> in <module>()
----> 1 ge.__next__() #从上面挂起的位置开始,但是后美女没有可执行的了,于是 __next__异常
StopIteration:
yield 与 return
- 一般函数都止于 return
- 作为生成器,有了yield 只是让程序在内部挂起,如果再之后还有return,遇到return就直接抛出SoptIteration异常而终止迭代
def r_return(n):
print('You taked me')
while n > 0:
print('before return')
return n
n -= 1
print('after return')
rr = r_return(3)
You taked me
before return
rr #retuen 后面的语句不会执行
3
def y_yield(n):
print('You taked me')
while n > 0:
print('before yield')
yield n
n -= 1
print('after yield')
yy = y_yield(3) #没哟执行函数体语句
yy.__next__() #开始执行,遇到 yield 返回值,并暂停
You taked me
before yield
3
yy.__next__() #从上次位置开始 ,遇到 yield 返回值,并暂停
after yield
before yield
2
yy.__next__() #从上次位置开始 ,遇到 yield 返回值,并暂停
after yield
before yield
1
yy.__next__() #没有满足条件的值,抛出异常
after yield
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-65-86493d8df2a1> in <module>()
----> 1 yy.__next__() #没有满足条件的值,抛出异常
StopIteration:
yield 与 return 相遇
def y_yield(n):
print('You taked me')
while n > 0:
print('before yield')
yield n
n -= 1
print('after yield')
return n
yy = y_yield(3) #没哟执行函数体语句
yy.__next__() #开始执行,遇到 yield 返回值,并暂停
You taked me
before yield
3
yy.__next__() #开始执行,遇到 yield 返回值,并暂停
after yield
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-67-e2663c79b073> in <module>()
----> 1 yy.__next__() #开始执行,遇到 yield 返回值,并暂停
StopIteration: 2
在斐波那契数列中用上 diely
#diely 实现
def fibs(max):
n,a,b = 0,0,1
while n < max:
yield b
a,b = b,a+b
n = n+1
if __name__ == "__main__":
f = fibs(10)
for i in f:
print(i)
1
1
2
3
5
8
13
21
34
55
#迭代器实现
class Fibs:
def __init__(self,max):
self.max = max
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
fib = self.a
if fib > self.max:
raise StopIteration()
self.a, self.b = self.b , self.a + self.b
return fib
fib = Fibs(50)
print(list(fib))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# list 实现
def fib_1(n):
result = [0,1]
for i in range(n-2):
result.append(result[-2] + result[-1])
return result
lst = fib_1(10)
print(lst)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# 递归 实现
def fib_2(n):
if n==0:
return 0
elif n==1:
return 1
else:
return fib_2(n-1) + fib_2(n-2)
f = fib_2(10)
for i in range(10):
print(fib_2(i))
0
1
1
2
3
5
8
13
21
34
生成器方法
- Python 2.5 以后生成器就有了一个新特性,就是在开始运行后能够为生成器提供新的值。,这就好似生成器和‘外界’之间进行数据交流
- send()
- send() 方法只能在 生成器运行并被挂起后才能使用,即 yield 至少执行一次,如果没有执行,就会报错
- 如果 send(None) 的话,就会返回上次输入的值
- close()
- 不用调用参数,用来关闭生成器
- throw()
- throw(type,value = None,traceback = None)
- 用于在生成器内部(生成器的当前挂起处或者未启动时的定义处)抛出一个异常(在yield表达式中)
def repeater(n):
while True:
n = (yield n)
r = repeater(4)
r.__next__() #生成器开始执行,遇到 yield 内部挂起。
4
r.send("hello") # 被挂起的程序,被唤醒,返回 send 发送的值 这就是在运行后能够为生成器提供值的含义。
'hello'
help(r.send)
Help on built-in function send:
send(...) method of builtins.generator instance
send(arg) -> send 'arg' into generator,
return next yielded value or raise StopIteration.
r.__next__() # 犹豫没有给参数,所以 yield 就只能返回None了
# 没有运行起来且挂起的生产器,直接send 就会报错。
r_1 = repeater(5)
r_1.send("how")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-77-1289d56d86b5> in <module>()
1 # 没有运行起来且挂起的生产器,直接send 就会报错。
2 r_1 = repeater(5)
----> 3 r_1.send("how")
TypeError: can't send non-None value to a just-started generator
r_1.send(None) #如果传None 就会返回上一个输入的值
5
参考:《跟着老齐学Python:从入门到精通》 作者:齐伟 电子工业出版社