其他分享
首页 > 其他分享> > 028—迭代器和生成器

028—迭代器和生成器

作者:互联网

什么是可迭代对象:

python中的所有存在的都是对象,如果对象有 __iter__方法,那么该对象就是可迭代对象

可以通过 dir(obj) 方法来查看对象所拥有的方法

t = ('a','b')
print(dir(t))

# ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']

通过成员运算符 in 来判断对象是不是可迭代对象

name = 'bone'
age = 18
li = [1,3,4]
t = ('a','b')
d = dict()
s = {1,2}

print('__iter__' in dir(name))  # True
print('__iter__' in dir(age))   # False
print('__iter__' in dir(li))    # True
print('__iter__' in dir(t))     # True
print('__iter__' in dir(d))     # True
print('__iter__' in dir(s))     # True

可迭代对象能够将其所有的内容一次性展示,所有它比较占内存,而且可迭代对象是不能直接循环取值的

学习循环时使用for执行循环了可迭代对象,其实内部是将可迭代对象先转换成了迭代器,然后循环取值的

for i in 'name':
    print(i)

迭代器

通过名字可以理解,它就是一个用于迭代的器具

什么是迭代器
name = 'bone'
age = 18
li = [1,3,4]
t = ('a','b')
d = dict()
s = {1,2}

print('__next__' in dir(name))  # False
print('__next__' in dir(age))   # False
print('__next__' in dir(li))    # False
print('__next__' in dir(t))     # False
print('__next__' in dir(d))     # False
print('__next__' in dir(s))     # False
可迭代对象能够转换成迭代器

通过 iter() 方法 或者 iter() 方法可以将一个可迭代对象转换为迭代器(iterator)

name = 'bone'
iteobj = iter(name)
print(iteobj)# <str_iterator object at 0x7f7f578a0040>


li = [1,3,4]
iteobj = li.__iter__()
print(iteobj)# <list_iterator object at 0x7ff7a4143850>
迭代器有什么用处

比如一个列表,存储了几千万的数据,想要查看这个列表,直接将其读取打印,那么会非常的占内存

再比如一个生活中的例子,一个文档或者Excel表格,特别大,当打开他们时,就会造成电脑变得很卡,甚至死机

有了迭代器的话就不一样了,可以一点一点的读取内容,当你读取第二个内容时,第一个内容就从内存消失了,这样就节省了内存消耗

使用迭代器

想要从迭代器取值,需要使用它的 next 方法,每执行一次, 就取出一个值

name = 'bone'
iteobj = iter(name)
print(iteobj)# <str_iterator object at 0x7f7f578a0040>
print(iteobj.__next__())
print(iteobj.__next__())
print(iteobj.__next__())
print(iteobj.__next__())
# b
# o
# n
# e

上面执行了4次__next__()方法,所有元素已经都取到了,如果再执行一次就会报错,要处理这个就需要自己去捕获处理了

print(iteobj.__next__())

#     print(iteobj.__next__())
# StopIteration

for循环和迭代器

for循环实际上就是将可迭代对象转成迭代器,然后执行__next__()方法,但是当它执行发现有 StopIteration 时,会处理这个异常

总结::

1、节省内存,进入下次迭代内容后,上一次的会从内存释放
2、它只能一直迭代向前,不能后退
3、无法知道迭代器中有多少个对象,只能等到抛出异常才知道

生成器

生成器其实可以叫做生成迭代器,它是本质就是个迭代器,也有 iternext 方法

创建生成器

一个函数如果有 yeild 关键字,那么它就是个生成器

def func(list_num):
    i = 0
    while i<len(list_num):
        yield list_num[i]
        i += 1
g = func([1,3,4,2,5])    # <generator object func at 0x7f808705fac0>

print('__iter__' in dir(g)) # True
print('__next__' in dir(g)) # True

生成器获取值:

生成器对象使用next() 或者 next()方法就可以取值

print(g.__next__()) # 1
print(next(g))  # 3

同样,超出后会报错

print(g.__next__()) # 1
print(next(g))  # 3
print(next(g))  # 4
print(next(g))  # 2
print(next(g))  # 5
print(next(g))  
# Traceback (most recent call last):
#     print(next(g))  # 3
# StopIteration

当然也可以for循环,因为它是迭代器

for i in g:
    print(i)
# 1
# 3
# 4
# 2
# 5

yield关键字

yield会返回一个值,这点和return一样,区别就是return会终止函数,但是yield不会,它会记录着状态并返回

return函数内只能有一个,但是yelid可以有多个

def func(list_num):
    i = 0
    while i<len(list_num):
        yield 1
        yield 2
        yield 3

        i += 1
g = func([1,3,4,2,5])  


print(next(g))  # 1
print(next(g))  # 2
print(next(g))  # 3
print(next(g))  # 1
print(next(g))  # 2

send方法

通过next方法可以获取yield的值,send也可以,send还有一个功能就是给yelid传值

这里直接使用send报错,提示不能把不是None的值发送到刚启动的生成器

def func(list_num):
    i = 0
    while i<len(list_num):
        s = yield 1
        print(s)
        i += 1
g = func([1,3,4,2,5])    # <generator object func at 0x7f808705fac0>

print(g.send('a'))  # TypeError: can't send non-None value to a just-started generator
print(g.send('a')) 

发送个None试一下

可以发现,s被赋值了’a’,这说明 yield 接收到了这个值,并赋值给了s

def func(list_num):
    i = 0
    while i<len(list_num):
        s = yield 1
        print(s)

        i += 1
g = func([1,3,4,2,5])    # <generator object func at 0x7f808705fac0>

print(g.send(None))
print(g.send('a'))

# 1
# a
# 1

不send(None),先next一下再send值也可以

def func(list_num):
    i = 0
    while i<len(list_num):
        s = yield 1
        print(s)

        i += 1
g = func([1,3,4,2,5])    # <generator object func at 0x7f808705fac0>

print(next(g))
print(g.send('a'))

# 1
# a
# 1

yelid…from

上面通过循环拿到列表的元素并且yield返回,这个操作可以通过 yield…from来实现

# yield list_num返回的是整个列表
def func(list_num):
    yield list_num
g = func([1,3,4,2,5])

print(next(g))  # [1, 3, 4, 2, 5]


# yield from list_num 返回每个元素
def func(list_num):
    yield from list_num
g = func([1,3,4,2,5])

print(next(g))  # 1
print(next(g))  # 3
print(next(g))  # 4

标签:__,迭代,生成器,iter,next,print,028,dir
来源: https://blog.csdn.net/c_first/article/details/113704825