Python基础--迭代器和生成器

1、迭代器

迭代器的特性:

    迭代是Python中最强有力的特性之一,能够把迭代当作是一种处理序列中元素的方式。

    能够直接做用于for循环的对象统称为可迭代对象(Iterable)。

    能够被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator)。
    
    全部的Iterable都可以经过内置函数iter()来转变为Iterator。

    出可迭代对象的个数会报错StopIteration,是一个结束信号

迭代器的优势:
    
    一、迭代器提供一种不依赖于索引的取值方式,这样就能够遍历那些没有索引的对象了(字典、集合、文件)
    二、迭代器和列表比较,迭代器是惰性计算,更节约内存

迭代器的缺点:
    一、永远不能获取迭代器的长度,使用不如列表索引取值灵活
    二、一次性的,只能日后取值,不能往前,不能像索引同样取得指定位置的值

2、查看可迭代和迭代器的方法

from collections import Iterable,Iterator
        s='hello'
        l=[1,2,3]
        t=(1,2,3)
        d={'a':1}
        set1={1,2,3,4}
        f=open('a.txt')

        #都是可迭代,只要对象有__iter__()方法,都是可迭代的
        s.__iter__()
        l.__iter__()
        t.__iter__()
        d.__iter__()
        set1.__iter__()
        f.__iter__()
               
        #查看是否能够迭代的
        print(isinstance(s,Iterable))

        #查看是不是迭代器,只有文件是迭代器
        f.__next__()

        print(isinstance(f,Iterator))

3、手动访问迭代器中的元素

一、问题

咱们要处理某个可迭代对象中的元素,可是基于某种缘由不能也不想使用for循环。

二、解决方案

要手动访问可迭代对象中的元素,可使用next()函数,而后本身编写代码来捕获stopiteration异常。例如:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
with open('passwd','r',encoding='utf8') as f:
    while True:
        try:
            line=next(f)
            print(line,end='')
        except StopIteration:
            break
#通常来讲,stopiteration异常是用来通知咱们迭代结束的,可是,若是是手动执行next(),也能够命令他返回一个值,好比None,示例以下:


with open('passwd','r',encoding='utf8') as f:
    while True:
        line=next(f,None)
        if line is None:
            break
        print(line,end='')
大多数状况下,咱们会用for循环来访问可迭代对象中的元素,可是,偶尔也会碰到须要对底层迭代机制作更精细状况的控制。所以,了解迭代实际发生了些什么是颇有必要的。for 循环也是先使用iter方法把要循环的对象生成一个迭代器,而后去遍历这个迭代器,遍历迭代器里的每一个元素
>>> items=[1,2,3]
>>> i=iter(items)     #===> i.__iter__()
>>> next(i)           #===> i.__next__()
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

4、生成器

生成器是一个包含yield关键字的函数,当它被调用时,在函数中的代码不会执行,而会返回一个迭代器。每次请求一个值,就会执行生成器中的代码,直到遇到一个yield或者return语句,yield语句一位着会生成一个值,return语句一位着生成器要中止执行(不在生成任何东西,return语句只有在一个生成器中使用时才能进行无参数调用)换句话说,生成器是由两部分组成:生成器的函数和生成器的迭代器,生成器的函数使用def定义,包括yield部分,生成器的迭代器是这个函数返回的部分。
def countdown(n):
    print('starting to count from',n)
    while n>0:
        yield n
        n-=1
    print('Done!')
g=countdown(5)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))

#执行结果以下
starting to count from 5
5
4
3
2
1

#函数中出现了yield语句,就会把这个函数转换成生成器。与普通的函数不一样,生成器只会在响应迭代操做是才会运行。调用时须要使用next方法才能执行,没执行一次,当遇到下一个yield时就会中止,下次执行next时,将从当前yield往下执行,知道遇到一个yield
生成器的本质就是一个迭代器,同时也是一个函数,调用的方式和函数相似,yield也至关于函数中的return
    yield和return的区别:return只能返回一次函数就会完全结束,而yield能返回屡次值
yield到底干了什么事情:
    一、yield把函数变成生成器(迭代器),把iter和next方法封装在函数内部
    二、函数在暂停一及继续下一次运行时的状态是yield保存

5、协程

from urllib.request import urlopen
def init(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        next(res)
        return res
    return wrapper

@init
def get():
    while True:
        url=yield
        res=urlopen(url).read()
        print(res)

g=get()  #g是一个迭代器
# next(g) #这里使用一个init的装饰器,自动作了next的工做
g.send("http://www.baidu.com")     #使用send把括号内的URL传递给yield
g.send('http://www.python.org')
g.send('http://www.163.com')
协程函数,是把yield改成表达式的方式,改过send代替next给yield传值
e.send于next(e)的区别
    一、若是函数内yield是表达式形式,那么必须先next(e),让生成器在第一个yield位置处等着
    二、两者的共同之处均可以让函数在上次暂停的位置继续运行,不同的地方在于,send在触发一下次代码的执行时,给yield传值
相关文章
相关标签/搜索