zoukankan      html  css  js  c++  java
  • Python学习-迭代器、生成器

    一、迭代器

    1. 可迭代对象

    我们知道字符串、列表、元组、字典、集合都可以使用for语句进行循环遍历,然后输出每一个元素,这些都是可迭代对象。

    检查对象是否是可迭代对象可以用两种方式去判断:

    (1)使用dir()查看对象包含的方法和函数, 如果能找到__iter__, 那么这个对象就是一个可迭代对象

    >>> lst = ['a', 'b', 'c']
    >>> dir(lst)  #查看对象包含的方法和函数
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__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']
    >>> dir(list)  #查看类中声明的方法和函数
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__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']
    >>>

    (2)使用isinstance进行判断

    >>> from collections import Iterable
    >>> lst = ['a', 'b', 'c']
    >>> isinstance(lst, Iterable) #结果为True,为可迭代对象
    True

    iterable翻译: 可迭代的; 可重复的; 迭代的

    此处只查看了列表类型对象, 其他类型的对象可以自己尝试.

    2. 迭代器

    概念: 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

    所谓的迭代器就是具有next方法的对象. 在调用next方法时, 迭代器会返回它的下一个值. 如果next方法被调用, 但迭代器没有值可以返回, 就会引发一个StopIteration异常.

    迭代器和可迭代对象有什么区别:

    (1) 可迭代对象不一定是迭代器, 但迭代器一定是可迭代对象

    (2) 可迭代对象有iter方法, 迭代器有iter和next方法; 可以使用iter方法将可迭代对象转为迭代器

    (3) 迭代器是惰性的, 只有当你使用next方法去取值的时候, 它才会返给你一个值

    判断对象是否是迭代器:

    >>> from collections import Iterator
    >>> isinstance((x for x in range(10)), Iterator)
    True
    >>> isinstance(['a', 'b'], Iterator)
    False
    >>> isinstance('hello', Iterator)
    False
    
    >>> g = (x * 2 for x in range(5))
    >>> isinstance(g, Iterator)
    True
    >>> next(g)
    0
    >>> next(g)
    2
    >>> next(g)
    4
    >>> next(g)
    6
    >>> next(g)
    8
    >>> next(g)  # 没有值返回时, 抛出异常StopIteration
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    >>>

    使用iter方法(或__iter__)将对象变为迭代器:

    >>> lst = ['a', 'b', 'c']
    >>> isinstance(lst, Iterator)
    False
    >>> lst_g = lst.__iter__()
    >>> isinstance(lst_g, Iterator)
    True
    >>> for ele in lst_g:
    ...     print(ele)
    ...
    a
    b
    c
    >>> dic = {'a': 1, 'b': 2}
    >>> isinstance(dic, Iterator)
    False
    >>> dic_g = iter(dic)
    >>> isinstance(dic_g, Iterator)
    True

    小结:

    凡是可作用于for循环的对象都是Iterable类型;

    凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

    集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

    二、生成器

    1. 先介绍一下列表生成式 (内容粘贴自廖雪峰老师的官方网站)

    列表生成式,是Python内置的非常简单却强大的可以用来创建list的生成式。

    列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

    举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11))

    >>> list(range(1, 11))
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    但如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循环:

    >>> L = []
    >>> for x in range(1, 11):
    ...    L.append(x * x)
    ...
    >>> L
    [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:

    >>> [x * x for x in range(1, 11)]
    [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。

    for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:

    >>> [x * x for x in range(1, 11) if x % 2 == 0]
    [4, 16, 36, 64, 100]

    还可以使用两层循环,可以生成全排列:

    >>> [m + n for m in 'ABC' for n in 'XYZ']
    ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

     2. 生成器

    通过列表生成式我们可以快速创建一个列表,这种方法生成列表,它会一次性的返回给我们全部元素,想想如果列表包含100万个元素,一次性返回会占用很大的内存空间,如果我们仅仅需要访问前面几个元素,这种方式生成的列表就比较浪费内存空间了。有没有一种方式,按照我们的需要,访问时给我们返回元素,不要像列表生成式一样一次全部返回。生成器就可以满足我们的这种需求,按需返回,可以调用next方法,生成器会返回它的下一个值,当没有值可以返回时,抛出StopIteration异常。实际使用中,我们一般使用for循环对生成器进行迭代。

    在python中创建生成器:

    (1)生成器函数

    def func():
        print('hello world')
        yield 'world'              #与定义的普通函数没有区别,只是含有yield关键字;函数中包含yield关键字即为生成器函数
        print('hello china')
        yield 'china'
    
    g = func()
    print(next(g))
    print(next(g))
    print(g)
    # 输出结果
    hello world
    world
    hello china
    china
    <generator object func at 0x108ad3468>

    (2)生成器表达式

    只要把一个列表生成式的[]改成(),就创建了一个generator。

    g = (x * x for x in range(5))
    print(g)
    for i in g:
        print(i)
    输出结果:
    <generator object <genexpr> at 0x10a845468>
    0
    1
    4
    9
    16
    
    
    lst = ['a', 'b', 'c', 'd']
    g2 = (x * 2 for x in lst)
    print(g2)
    while 1:
        try:
            print(next(g2))
        except StopIteration:
            break
    输出结果:
    <generator object <genexpr> at 0x10395b468>
    aa
    bb
    cc
    dd
  • 相关阅读:
    Android中Handler与Message的简单实例
    折腾蛋疼的Ubuntu1204LTS的U盘安装
    sgs_intro
    把杀某程序封装成sh
    boost 程序库完全开发_ch4_utility
    VS2005 warning C4819处理办法(提示代码页有不兼容的字符)
    Ubuntu1204LTS下xynxyc编译Emacs24.02
    当VS05调试赋值不对时,小心只是IDE的watch在骗你.....
    很好的boost学习资料
    C++实现Creational Singleton模式
  • 原文地址:https://www.cnblogs.com/gandoufu/p/9330473.html
Copyright © 2011-2022 走看看