python热爱者

Python - 迭代器and生成器

2017-12-07  本文已影响12人  丘山Ivan

迭代器

仿写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

分析:

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()

Python3 中只有range() ,和Python2 中的xrange()是一样的可以迭代的。

range(10000)
range(0, 10000)

生成器(generator)

#生成器
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

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

生成器方法

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:从入门到精通》 作者:齐伟 电子工业出版社

上一篇 下一篇

猜你喜欢

热点阅读