欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python学习日记(十) 生成器和迭代器

程序员文章站 2022-03-07 10:39:42
使用dir()我们可以知道这个数据类型的内置函数有什么方法: 1.迭代器 iterable:可迭代的 迭代就是将数据能够一个一个按顺序取出来 上面数据类型返回为真说明它是可以迭代的,反之是不可迭代的 可迭代协议: 就是内部要有一个__iter__()来满足要求 当一个具有可迭代的数据执行__iter ......

使用dir()我们可以知道这个数据类型的内置函数有什么方法:

print(dir(int))  
print(dir(bool))
print(dir([]))
print(dir({}))
print(dir(set))

 

1.迭代器

iterable:可迭代的

迭代就是将数据能够一个一个按顺序取出来

s = 'abc'
print('__iter__' in dir(s))      #true
li = [1,2]
print('__iter__' in dir(li))     #true
b = false
print('__iter__' in dir(b))      #false
i = 123
print('__iter__' in dir(i))      #false
dic = {}
print('__iter__' in dir(dic))    #true
set1 = set()
print('__iter__' in dir(set1))   #true

上面数据类型返回为真说明它是可以迭代的,反之是不可迭代的

可迭代协议:

就是内部要有一个__iter__()来满足要求

当一个具有可迭代的数据执行__iter__()它将返回一个迭代器的内存地址

print('abc'.__iter__()) #<str_iterator object at 0x005401f0>

这里的iterator的意思是迭代器

迭代器协议:

现在有一个列表我们来看看它本身和在执行了__iter__()之后的方法有什么不同:

li = [1,2,3,'a']
print(dir(li))  #['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
print(dir(li.__iter__()))   #['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
'''求两者的差集'''
print(set(dir(li.__iter__())) - set(dir(li)))   #{'__length_hint__', '__setstate__', '__next__'}
__length_hint__()的作用是求元素的长度
__setstate__()的作用是指定索引值从哪里开始迭代
__next__()的作用可以让值一个一个的取出

在之前用到的for循环我们就是用__next__()这种方法进行取值,现在我们可以模拟for来写一个函数:
li = [1,2,3,'a']
def getitem(li):
    iterator = li.__iter__()
    while true:
         print(iterator.__next__())
getitem(li)
# 1
# 2
# 3
# a
#stopiteration 如果找不到元素就会报错

如何处理掉这个异常?

li = [1,2,3,'a']
def getitem(li):
    iterator = li.__iter__()
    while true:
        try:
            print(iterator.__next__())
        except stopiteration:
            break
getitem(li)
# 1
# 2
# 3
# a

迭代器遵循迭代器协议:必须要有__iter__()和__next__()

迭代器的好处:

  a.从容器类型中一个一个的取值,会把所有的值都取到

  b.节省内存的空间

     迭代器并不会在内存中占用一大块内存,而是随着循环每次生成一个,每一次使用__next__()来给值

range():

print(range(10000000))  #range(0, 10000000)

实际上range()在调用的时候并没有真正生成这么多的值,如果真的生成的话那么内存可能会溢出

print('__iter__' in dir(range(10)))     #true   
print('__next__' in dir(range(10)))     #false
from collections import iterable
from collections import iterator
print(isinstance(range(10),iterable))    #true  是一个可迭代对象
print(isinstance(range(10),iterator))    #false 在执行后得到的结果并不是一个迭代器

迭代器总结:

1.可以被for循环的都是可迭代的

2.可迭代的内部都有__iter__()方法

3.只要是迭代器一定可以迭代

4.可迭代的变量.__iter__()方法可以得到一个迭代器

5.迭代器中的__next__()方法可以一个一个的获取值

6.for循环实际上就是在使用迭代器

 

2.生成器

生成器函数

本质上就是我们自己写的函数,只要含有yield关键字的函数就是生成器函数,yield不能和return共用且需要写在函数内部

def generator():        #生成器函数
    print('a')
    yield 5
ret = generator()       #ret是一个生成器
print(ret)              #<generator object generator at 0x00503f00>

生成器函数每次执行的时候会得到一个生成器作为返回值

如果要返回函数值:

def generator():        #生成器函数
    print('a')
    yield 5
    print('b')
    yield 4
g = generator()        #ret是一个生成器
print(g)               #<generator object generator at 0x00503f00>
ret = g.__next__()
print(ret)              #a
                        #5
print('---------')
ret = g.__next__()
print(ret)              #b
                        #4

执行顺序:

Python学习日记(十) 生成器和迭代器

使用for循环遍历生成器:

def generator():        #生成器函数
    print('a')
    yield 5
    print('b')
    yield 4
    print('c')
    yield 6
g = generator()       #ret是一个生成器
for i in g:
    print(i)    
# a
# 5
# b
# 4
# c
# 6

监听文件例子:

def tail(filename):
    f = open(filename,encoding='utf-8')
    while true:
        line = f.readline()
        if line.strip():
             yield line.strip()
g = tail('tail')
for i in g:
    if 'python' in i:
        print('******',i)   
# ****** python
# ****** asd python