zoukankan      html  css  js  c++  java
  • Python可迭代对象、迭代器和生成器

    Python可迭代对象、迭代器和生成器

    python 函数 表达式 序列 count utf-8 云栖征文 python可迭代对象 python迭代器 python生成器

    摘要: 8.1 可迭代对象(Iterable) 大部分对象都是可迭代,只要实现了__iter__方法的对象就是可迭代的。 __iter__方法会返回迭代器(iterator)本身,例如: >>> lst = [1,2,3] >>> lst.__iter__() <listiterator objec...

    8.1 可迭代对象(Iterable)
    大部分对象都是可迭代,只要实现了__iter__方法的对象就是可迭代的。
    __iter__方法会返回迭代器(iterator)本身,例如:
    >>> lst = [1,2,3]
    >>> lst.__iter__()
    <listiterator object at 0x7f97c549aa50>
    Python提供一些语句和关键字用于访问可迭代对象的元素,比如for循环、列表解析、逻辑操作符等。
    判断一个对象是否是可迭代对象:
    >>> from collections import Iterable  # 只导入Iterable方法
    >>> isinstance('abc', Iterable)     
    True
    >>> isinstance(1, Iterable)     
    False
    >>> isinstance([], Iterable)
    True
    这里的isinstance()函数用于判断对象类型,后面会讲到。
    可迭代对象一般都用for循环遍历元素,也就是能用for循环的对象都可称为可迭代对象。
    例如,遍历列表:
    >>> lst = [1, 2, 3]
    >>> for i in lst:
    ...   print i
    ...
    1
    2
    3

    博客地址:http://lizhenliang.blog.51cto.com and https://yq.aliyun.com/u/lizhenliang
    QQ群:323779636(Shell/Python运维开发群) 


    8.2 迭代器(Iterator)
    具有next方法的对象都是迭代器。在调用next方法时,迭代器会返回它的下一个值。如果next方法被调用,但迭代器没有值可以返回,就会引发一个StopIteration异常。
    使用迭代器的好处:
    1)如果使用列表,计算值时会一次获取所有值,那么就会占用更多的内存。而迭代器则是一个接一个计算。
    2)使代码更通用、更简单。
       8.2.1 迭代器规则
       回忆下在Python数据类型章节讲解到字典迭代器方法,来举例说明下迭代器规则:
    >>> d = {'a':1, 'b':2, 'c':3}
    >>> d.iteritems()
    <dictionary-itemiterator object at 0x7f97c3b1bcb0>
     
    # 判断是否是迭代器
    >>> from collections import Iterator
    >>> isinstance(d, Iterator)
    False
    >>> isinstance(d.iteritems(), Iterator)
    True
     
    # 使用next方法。
    >>> iter_items = d.iteritems()
    >>> iter_items.next()
    ('a', 1)
    >>> iter_items.next()
    ('c', 3)
    >>> iter_items.next()
    ('b', 2)
    由于字典是无序的,所以显示的是无序的,实际是按照顺序获取的下一个元素。
       8.2.2 iter()函数
       使用iter()函数转换成迭代器:
    语法:
      iter(collection) -> iterator
      iter(callable, sentinel) -> iterator
    >>> lst = [1, 2, 3]
    >>> isinstance(lst, Iterator)
    False
    >>> lst.next()  # 不是迭代器是不具备next()属性的
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'list' object has no attribute 'next'
    >>> iter_lst = iter(lst)             
    >>> isinstance(iter_lst, Iterator)
    True
     
    >>> iter_lst.next()
    1
    >>> iter_lst.next()
    2
    >>> iter_lst.next()
    3
       8.2.3 itertools模块
    itertools模块是Python内建模块,提供可操作迭代对象的函数。可以生成迭代器,也可以生成无限的序列迭代器。
    有下面几种生成无限序列的方法:
    count([n]) --> n, n+1, n+2, ...
    cycle(p) --> p0, p1, ... plast, p0, p1, ...
    repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times 
    也有几个操作迭代器的方法:
       islice(seq, [start,] stop [, step]) --> elements from
    chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ...
    groupby(iterable[, keyfunc]) --> sub-iterators grouped by value of keyfunc(v) 
    imap(fun, p, q, ...) --> fun(p0, q0), fun(p1, q1), ...
    ifilter(pred, seq) --> elements of seq where pred(elem) is True
     1)count生成序列迭代器
    >>> from itertools import *  # 导入所有方法
          # 用法 count(start=0, step=1) --> count object
    >>> counter = count()    
    >>> counter.next()
    0
    >>> counter.next()
    1
    >>> counter.next()
    2
    ...... 
    可以使用start参数设置开始值,step设置步长。
        2)cycle用可迭代对象生成迭代器
          # 用法 cycle(iterable) --> cycle object
    >>> i = cycle(['a', 'b', 'c'])  
    >>> i.next()
    'a'
    >>> i.next()
    'b'
    >>> i.next()
    'c'
       3)repeat用对象生成迭代器
    # 用法 repeat(object [,times]) -> create an iterator which returns the object,就是任意对象
    >>> i = repeat(1)
    >>> i.next()
    1
    >>> i.next()
    1
    >>> i.next()
    1
    ......
    可使用无限次。
     
    也可以指定次数:
         >>> i = repeat(1, 2)
    >>> i.next()
    1
    >>> i.next()
    1
    >>> i.next()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
       4)islice用可迭代对象并设置结束位置
          # 用法 islice(iterable, [start,] stop [, step]) --> islice object
    >>> i = islice([1,2,3],2)   
    >>> i.next()             
    1
    >>> i.next()
    2
    >>> i.next()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    正常的话也可以获取的3。
       5)chain用多个可迭代对象生成迭代器
    # 用法 chain(*iterables) --> chain object
    >>> i = chain('a','b','c')
    >>> i.next()
    'a'
    >>> i.next()
    'b'
    >>> i.next()
    'c'
       6)groupby将可迭代对象中重复的元素挑出来放到一个迭代器中
    # 用法 groupby(iterable[, keyfunc]) -> create an iterator which returns
    >>> for key,group in groupby('abcddCca'):
    ...   print key,list(group)               
    ...
    a ['a']
    b ['b']
    c ['c']
    d ['d', 'd']
    C ['C']
    c ['c']
    a ['a']
    groupby方法是区分大小写的,如果想把大小写的都放到一个迭代器中,可以定义函数处理下:
    >>> for key,group in groupby('abcddCca', lambda c: c.upper()):
    ...   print key, list(group)
    ...
    A ['a']
    B ['b']
    C ['c']
    D ['d', 'd']
    C ['C', 'c']
    A ['a']
       7)imap用函数处理多个可迭代对象
    # 用法 imap(func, *iterables) --> imap object
    >>> a = imap(lambda x, y: x * y,[1,2,3],[4,5,6])   
    >>> a.next()
    4
    >>> a.next()
    10
    >>> a.next()
    18
       8)ifilter过滤序列
    # 用法 ifilter(function or None, sequence) --> ifilter object
    >>> i = ifilter(lambda x: x%2==0,[1,2,3,4,5])
    >>> for i in i:
    ...   print i
    ...
    2
    4
    当使用for语句遍历迭代器时,步骤大致这样的,先调用迭代器对象的__iter__方法获取迭代器对象,再调用对象的__next__()方法获取下一个元素。最后引发StopIteration异常结束循环。
    8.3 生成器(Generator)
    什么是生成器?
    1)任何包含yield语句的函数都称为生成器。
    2)生成器都是一个迭代器,但迭代器不一定是生成器。
    8.3.1 生成器函数
    在函数定义中使用yield语句就创建了一个生成器函数,而不是普通的函数。
    当调用生成器函数时,每次执行到yield语句,生成器的状态将被冻结起来,并将结果返回__next__调用者。冻结意思是局部的状态都会被保存起来,包括局部变量绑定、指令指针。确保下一次调用时能从上一次的状态继续。
    以生成斐波那契数列举例说明yield使用:
    斐波那契(Fibonacci)数列是一个简单的递归数列,任意一个数都可以由前两个数相加得到。
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    def fab(max):
        n, a, b = 0, 0, 1
        while n < max:
            print b
            a, b = b, a + b
            n += 1
    fab(5)
     
    # python test.py
    1
    1
    2
    3
    5
    使用yied语句,只需要把print b改成yield b即可:
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    def fab(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            # print b
            a, b = b, a + b
            n += 1
    print fab(5)
     
    # python test.py
    <generator object fab at 0x7f2369495820>
    可见,调用fab函数不会执行fab函数,而是直接返回了一个生成器对象,上面说过生成器就是一个迭代器。那么就可以通过next方法来返回它下一个值。
    >>> import test
    >>> f = test.fab(5)   
    >>> f.next()       
    1
    >>> f.next()                               
    1
    >>> f.next()
    2
    >>> f.next()
    3
    >>> f.next()
    5
    每次fab函数的next方法,就会执行fab函数,执行到yield b时,fab函数返回一个值,下一次执行next方法时,代码从yield b的吓一跳语句继续执行,直到再遇到yield。
    8.3.2 生成器表达式
    在第四章 Python运算符和流程控制章节讲过,简化for和if语句,使用小括号()返回一个生成器,中括号[]生成一个列表。
    回顾下:
    # 生成器表达式
    >>> result = (x for x in range(5))
    >>> result
    <generator object <genexpr> at 0x030A4FD0>
    >>> type(result)
    <type 'generator'>
     
    # 列表解析表达式
    >>> result = [ x for x in range(5)]
    >>> type(result)
    <type 'list'>
    >>> result
    [0, 1, 2, 3, 4]
    第一个就是生成器表达式,返回的是一个生成器,就可以使用next方法,来获取下一个元素:
    >>> result.next()
    0
    >>> result.next()
    1
    >>> result.next()
    2
    ......
  • 相关阅读:
    第一款上位机的笔记(MFC)——VS2010
    C++随笔(四)
    C++随笔(三)
    C++随笔(二)障眼法
    C++随笔
    matlab中的数据图像拟合
    在keil中调试汇编程序
    redis常见的面试题及答案
    spring定时任务的几种实现方式
    【SpringMVC】从Fastjson迁移到Jackson,以及对技术选型的反思
  • 原文地址:https://www.cnblogs.com/weiman3389/p/6044963.html
Copyright © 2011-2022 走看看