博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
迭代器和生成器(难点)
阅读量:5268 次
发布时间:2019-06-14

本文共 5519 字,大约阅读时间需要 18 分钟。

11.1.可迭代对象(iterable):          
内部实现了__iter__方法
可以被迭代满足要求的就叫做可迭代协议。
iterable:可迭代的------对应的标志
迭代概念:一个一个取值,就像for循环一样取值
字符串,列表,元组,集合,字典都是可迭代的
11.2迭代器协议(iterator):           
内部实现了__iter__,__next__方法 
可以被next()函数调用并且不断返回下一个值的对象称为迭代器
所有的iterable()均可以通过内置函数iter()转变成iterator
 iterator继承自iterable,iterator包含iter()和next()方法,而iterable仅仅包含iter()
 
迭代器的优点:如果用了迭代器,
节约内存,方便操作
print(dir([1, 2].__iter__()))   # 查看列表迭代器的所有方法print(dir([1, 2]))   #  查看列表的所有方法print(set(dir([1, 2].__iter__()))-set(dir([1, 2])))    # 对上面两者求差集,去重---{
'__setstate__', '__length_hint__', '__next__'}
iter_l = [1, 2, 3, 4, 5, 6].__iter__()    # 后缀必须有这个print(iter_l.__length_hint__())  # 获取迭代器中元素的长度---6print(iter_l.__setstate__(4))   # 根据索引指定从哪里开始迭代---Noneprint(iter_l.__next__())print(iter_l.__next__())print(iter_l.__next__())   # 一个一个的取值print(next(iter_l))   #  next(iter_l)和iter_l.__next__()方法一样,推荐用next(iter_l)这个---1---2---3---4

 采用for循环模拟可迭代机制:

li = [1,5,78,1,534,34,51,3,15,6]lis = li.__iter__()while True:    try:        print(next(lis))    except:        #采用try过滤掉报错        break
 
11.3可迭代和迭代器的相同点:都可以用for循环
11.4可迭代和迭代器的不同点:就是迭代器内部多实现了一个__next__方法
11.5判断迭代器和可迭代的方法:
第一种:判断内部是不是实现了__next__方法
'__iter__' in dir(str)  # 如果__iter__在这个方法里面,就是可迭代的。s = 'abc'print('__iter__' in str(s))---False

 第二种:

    Iterable 判断是不是可迭代对象
    Iterator 判断是不是迭代器
    用法:
from collections import Iterablefrom collections import Iterators = 'abc'    # 随便给一个字符串print(isinstance(s, Iterable))  # isinstance 判断类型的print(isinstance(s, Iterator))---True---False

11.6生成器(Generator )(难点):

生成器就是一种迭代器,它拥有next方法而且行为与迭代器完全相同,生成器是一种普通函数语法定义的迭代器。任何包含yield语句的函数成为生成器。
我们定义一个生成器就是定义一个普通函数,但是函数里面有yield关键字,调用生成器函数时会返回一个生成器。
生成器的好处,就是一下子不会在内存中生成太多的数据
 
yield 生成器的运行机制:
当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把yield 的参数给你,之后生成器就不会往下继续运行。 当你问他要下一个数时,他会从上次的状态开始运行,直至出现yield语句,把参数给你,之后停下。如此反复直至退出函数。
yield的使用:
在python中,当你定义一个函数,使用了yield关键字时,这个函数就是一个生成器,它的执行会和其他普通的函数有很多不同,函数返回的是一个对象,而不是你平常所用return语句那样,能得到结果值。
如果想取得值,那得调用next()函数
生成器的本质:就是一个迭代器
def h():    print 'To be brave'    yield 5h()             # 调用h()之后,print语句并没有执行,因为它有yield表达式

我们通过next()语句让它执行。next()语句将恢复Generator执行,并直到下一个yield表达式处。比如:

def h():    print 'Wen Chuan'    yield 5    print 'Fighting!'c = h()print(next(c))  # c. 每当调用一次迭代器的next函数,生成器函数运行到yield之处,           #  返回yield后面的值且在这个地方暂停,所有的状态都会被保持住,直到下次next函数被调用,或者碰到异常循环退出。--- Wen Chuan---5                        # 当我们再次调用next(c)时,会继续执行,直到找到下一个yield表达式,否则报错def h():    print 'Wen Chuan'    yield 5    print 'Fighting!'c = h()c.__next__()                # 这里直接调用了next,所以没有打印yield后面的值,和上面对比一下---Wen Chuan

这里多取值会直接报错:

def func():    print('aaaaaaaaaaa')    a = 1    yield a    print('bbbbbb')    yield 12  # 返回第二个值ret = func()    # 得拿到一个生成器print(ret)      # 返回的是一个地址print(next(ret))    # 取第一个值,'aaaaaa', 1print(next(ret))    # 取第二个值, 'bbb', 12print(next(ret))    # 取第三个值,会报错,因为没有yield第三个值 #注意,这里如果直接连续print(next(func())),一直只会打印第一个yield的内容,注意这里的区别。 这和上面ret是两个不同的生成器。

例:创建斐波那契数列:

def fib(max):    (a, b) = (1, 1)    while a < max:        yield a      # generators return an iterator that returns a stream of values.       (a, b)  = (b, a+b)for n in fib(15):    print(n)程序运行到yield这行时,就不会继续往下执行。而是返回一个包含当前函数所有参数的状态的iterator对象。 目的就是为了第二次被调用时,能够访问到函数所有的参数值都是第一次访问时的值,而不是重新赋值。程序第一次调用时:def fib(max):    (a, b) = (1, 1)    while a < max:        yield a      #  这时a,b值分别为1,1,当然,程序也在执行到这时,返回        (a, b) = (b, a+b)程序第二次调用时:    从前面可知,第一次调用时,a,b=1,1,那么,我们第二次调用时(其实就是调用第一次返回的iterator对象的next()方法),程序跳到yield语句处,执行a,b = b, a+b语句,此时值变为:(a,b = 1, (1+1)) => (a,b = 1, 2)程序继续while循环,当然,再一次碰到了yield a 语句,也是像第一次那样,保存函数所有参数的状态,返回一个包含这些参数状态的iterator对象。等待第三次的调用....
# 通过类的方法来实现斐波那契数列class Fib:      def __init__(self, max):          self.max = max      def __iter__(self):          self.a = 0          self.b = 1          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

通过yield生成全排列:

def perm(items, n = None):      if n is None:          n = len(items)      for i in range(len(items)):          v = items[i:i+1]          if n==1:              yield v          else:              rest = items[:i] + items[i+1:]              for p in perm(rest, n-1):                  yield v + p  def comb(items, n = None):      if n is None:          n = len(items)      else:          for i in range(len(items)):              v = items[i:i+1]              if 1 == n:                  yield v              else:                  rest = items[i+1:]                  for c in comb(rest, n-1):                      yield v + c

11.6.1 列表推导式 和生成器表达式

1.把列表解析的[]换成()得到的就是生成器表达式

2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数(sum,sorted,math等),也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:

#列表解析sum([i for i in range(100000000)])#内存占用大,机器容易卡死    不要运行,千万不要运行 #生成器表达式sum(i for i in range(100000000))#几乎不占内存    # 使用sorted函数 >>>sorted(x**2 for x in range(4)) [0,1,4,9]

列表推导式链接------

# 注意:对于生成器

g = (i for i in range(2))print(list(g))print(list(g))---[0, 1]---[]

这里为什么第二次再次打印为空了呢?它其实只能被调用一次,第一次调用完第二次调用的时候就没有了。生成器,生成器并不会二次生成,一次使用完就不会再有第二次了

见这么个面试题:

def demo():    for i in range(4):        yield ig=demo()g1=(i for i in g)g2=(i for i in g1)print(list(g1))print(list(g2))

11.6.2 yield from(两个例子结果相同,比较一下两者区别)

def func():    yield from 'AB'    yield from [1, 2, 3]g = func()print(list(g))②def func():    for i in 'AB':        yield i    for i in [1, 2, 3]:        yield ig = func()print(list(g))

 

转载于:https://www.cnblogs.com/LearningOnline/p/8463925.html

你可能感兴趣的文章
Oracle——SQL基础
查看>>
项目置顶随笔
查看>>
Redis的安装与使用
查看>>
P1970 花匠
查看>>
java语言与java技术
查看>>
NOIP2016提高A组五校联考2总结
查看>>
RabbitMQ学习系列三:.net 环境下 C#代码订阅 RabbitMQ 消息并处理
查看>>
Python日期计算
查看>>
对其他团队的项目的意见或建议
查看>>
iOS 项目的编译速度提高
查看>>
机房收费系统——报表
查看>>
How to unshelve many shelves at same time
查看>>
table中checkbox选择多行
查看>>
动态链接库
查看>>
Magento开发文档(三):Magento控制器
查看>>
使用Docker官方的Django包【转】
查看>>
SuperSocket 学习
查看>>
给培训学校讲解ORM框架的课件
查看>>
此实现不是 Windows 平台 FIPS 验证的加密算法的一部分
查看>>
性能调优攻略
查看>>