首页 > 编程语言 > 详细

python中的迭代器与生成器

时间:2020-07-21 22:30:51      阅读:83      评论:0      收藏:0      [点我收藏+]

迭代器

‘__iter__‘ 方法的就是可迭代对象

列举些可迭代对象:str,list,tuple,dict,set,range,文件句柄

获取一个对象的所有的方法dir();把每个方法以字符串的格式放在一个列表中返回回来

s1 = ‘asdfas‘
print(dir(s1))
#结果
[‘__add__‘, ‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__getnewargs__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__init_subclass__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__mod__‘, ‘__mul__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__rmod__‘, ‘__rmul__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘capitalize‘, ‘casefold‘, ‘center‘, ‘count‘, ‘encode‘, ‘endswith‘, ‘expandtabs‘, ‘find‘, ‘format‘, ‘format_map‘, ‘index‘, ‘isalnum‘, ‘isalpha‘, ‘isascii‘, ‘isdecimal‘, ‘isdigit‘, ‘isidentifier‘, ‘islower‘, ‘isnumeric‘, ‘isprintable‘, ‘isspace‘, ‘istitle‘, ‘isupper‘, ‘join‘, ‘ljust‘, ‘lower‘, ‘lstrip‘, ‘maketrans‘, ‘partition‘, ‘replace‘, ‘rfind‘, ‘rindex‘, ‘rjust‘, ‘rpartition‘, ‘rsplit‘, ‘rstrip‘, ‘split‘, ‘splitlines‘, ‘startswith‘, ‘strip‘, ‘swapcase‘, ‘title‘, ‘translate‘, ‘upper‘, ‘zfill‘]

判断所有方法里有没有 __iter__

s1 = ‘asdfas‘
print(‘__iter__‘ in dir(s1))
#True

进入重点(迭代器)

  • 迭代器的定义
    • 字面意思:更新迭代,器:工具:可更新迭代的工具
    • 专业角度:内部含有__iter__方法并且含有‘__next__‘方法的对象就是迭代器。
    • 可以判断是否是迭代器:‘__iter__‘and‘__next__‘在不在dir(对象)
  • 可迭代对象是不能直接for循环取值的,之所以我们能是因为for循环内部自动帮我们转化成迭代器了

可迭代对象可以转化成迭代器

s = ‘qwer‘
s1 = iter(s)
print(‘__next__‘ in dir(s1))
#变量 = iter(要转化的可迭代对象)

#或者这样

s = ‘qwer‘
s1 = s.__iter__()
print(‘__next__‘ in dir(s1))
#(iter()函数就是调用的这个方法)

迭代器是用next()一个一个取值的

s = ‘qwer‘
s1 = iter(s)  #s1 = s.__iter__()
print(‘__next__‘ in dir(s1))
print(next(s1))  #s1.__next__()
print(next(s1))  #s1.__next__()
print(next(s1))  #s1.__next__()
print(next(s1))  #s1.__next__()
#少一个next可以,那就少取一个值,多一个不应,就报错(停止迭代的这么一个错误)
‘‘‘
True
q
w
e
r
‘‘‘

练习:把一个列表转化成迭代器,并用next一个一个取值

li = [11,22,33,44,55,66]
l1 = iter(li)
#print(‘__next__‘ in dir(l1))
print(next(l1))
print(next(l1))
print(next(l1))
print(next(l1))
print(next(l1))
print(next(l1))

优点

  1. 节省内存。
  2. 惰性机制:next一次就取一个值
  3. 有一个迭代器模式可以很好的解释上面这两条:迭代是数据处理的基石。扫描内存中放不下的数据集时,我们要找到一种惰性获取数据项的方式,即按需一次获取一个数据项。这就是迭代器模式。

缺点

  1. 速度慢。以时间换空间
  2. 不走回头路。

迭代器与可迭代对象的对比

  • 可迭代对象是一个私有的方法比较多,操作灵活(比如列表,字典的增删改查,字符串的常用操作方法等),比较直观,存储数据相对少(几百万个对象,8G内存是可以承受的)的一个数据集
  • 应用:当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。
  • 迭代器是一个非常节省内存,可以记录取值位置,可以直接通过循环+next方法取值,但是不直观,操作方法比较单一的数据集。
  • 应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭代器)。

while循环模拟for循环机制

利用while循环模拟for循环对可迭代对象进行取值的机制

li = [1,2,3,4,5,6,7]
obj = iter(li)#将可迭代对象转化成迭代器
while 1:
    try:
        print(next(obj))
    except StopIteration:
        break

生成器generator

生成器:python社区,生成器与迭代器看成是一种。生成器的本质就是迭代器。唯一的区别:生成器是我们自己用python代码构建的数据结构。迭代器都是提供的,或者转化得来的。

只要有yield就是生成器

  • 获取生成器的三种方式:
    • 生成器函数
    • 生成器表达式
    • python内部提供的一些
  • 生成器函数获得生成器:yield
    • 生成器函数,用函数名加()不执行函数(和函数的区别)
    • yield:只要函数中有yield那么它就是生成器函数,而不是函数了
    • 生成器函数可以存在多个yield,一个yield对应一个next。yield不会结束生成器函数(return一个函数只能有一个,可以有多个但是执行到第一个就结束了)
    • 一个next()对应一个yield,并且把yield的值返回给next()
def func():
    print(111)
    print(222)
    yield 3
    a = 1
    b = 2
    c = a+b
    print(c)
    yield 4
ret = func()
print(next(ret))
print(next(ret))
‘‘‘
111
222
3
3
4
‘‘‘

yield from

yield将一个可迭代对象,变成一个生成器

def func():
    l1 = [1,2,3,4,5]
    yield from l1
    #yield from l1 相当于
    ‘‘‘
    yield 1
    yield 2
    yield 3
    yield 4
    yield 5
    ‘‘‘
    #yield from 将l1这个列表变成了迭代器返回
ret = func()
print(next(ret))
print(next(ret))
print(next(ret))
‘‘‘
1
2
3
‘‘‘

列表推导式

用一行代码构建一个比较复杂有规律的列表。

li = []
for i in range(1,11):
    li.append(i)
print(li)
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

l1 = [i for i in range(1,11)]
print(l1)
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

列表推导式:分为两类

  • 循环模式:每一个元素都留下来

    • [变量(或加工后的变量) for 变量 in iterable]
      
  • 筛选模式:满足条件的留下来,不满足扔了

    • [变量(或加工后的变量) for 变量 in iterable if 条件]
      
      #列表中名字有2个e的所有名字留下并大写
      names = [[‘Tom‘,‘Billy‘,‘Jefferson‘,‘Andrew‘,‘Wesley‘,‘Steven‘,‘Joe‘],        [‘Alice‘,‘Jill‘,‘Ana‘,‘Wendy‘,‘Jennifer‘,‘Sherry‘,‘Eva‘]]
      li = [i.upper() for i in names[0]+names[1] if i.count(‘e‘)==2]
      li = [j.upper() for i in names for j in i if j.count(‘e‘)==2]
      print(li)
      

生成器表达式

生成器表达式:与列表推导式的写法几乎一模一样。也有循环模式,筛选模式,多层循环构建,写法上只有一个不同:[ ] 换成 ( )

print([i for i in range(1,11)])#列表推导式
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print((i for i in range(1,11)))#生成器表达式
#<generator object <genexpr> at 0x000001E2308B2228>
obj = (i for i in range(1,11))
print(next(obj))#1
print(next(obj))#2
print(next(obj))#3
print(next(obj))#4

#或者这样for循环
obj = (i for i in range(1,11))
for i in obj:
    print(i)
    ‘‘‘
1
2
3
4
5
6
7
8
9
10
    ‘‘‘

python中的迭代器与生成器

原文:https://www.cnblogs.com/libra-ziqing/p/13356730.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!