美文网首页
Python高级特性-2

Python高级特性-2

作者: MrTrying | 来源:发表于2018-07-23 22:34 被阅读20次

    列表生成式

    #生成[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    #直接创建
    arr = list(range(0, 10))
    print(arr)
    
    #列表生成式
    arr = [x for x in range(0, 10)]
    print(arr)
    

    上面两段代码效果相同,都是生成0~9的list,第二段代码使用的是列表生成式。

    其中第二个x表示for..in迭代的元素,第一个x表示添加到list中的元素;第一个x还可以替换成其他的,例如表达式

    arr = [0 for x in range(0, 10)]
    print(arr)
    #输出:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    
    arr = [x*2 for x in range(0, 10)]
    print(arr)
    #输出:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    

    for..in后面还能加上if条件判断。抱着怀疑的态度,试了试在直接使用for..in进行迭代的情况下添加if判断,结果报错了。

    arr = [x * x for x in range(0, 10) if x % 2 == 0]
    print(arr)
    #输出:[0, 4, 16, 36, 64]
    

    还有一个比较强大的地方,列表生成式支持for..in的叠加,也就是循环的嵌套

    arr = [m + n for m in '123'for n in 'abc']
    print(arr)
    #输出:['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']
    

    for..in所支持的迭代类型,在列表生成式中都是可以使用的,例如字符串,dirt,dirt.values(),dirt.items()等,都是可以使用的。而在列表生成式的第一个x的位置,出了表达式,还支持第二个x类型所支持的函数。

    生成器(generator)

    列表生成式是一次直接创建了一个完整的list,而生成器则不必创建一个完整的list,可以一边循环一边创建list中的元素,这样跟更加节省内存。

    #生成式中的[]变成()
    g = (x for x in range(10))
    

    这样就创建了一个generator,并不是list,可以通过next(g)函数获取生成的元素,next会获取下一个生成的元素。而generator也是支持迭代的,这样才更加合理,不需要无限的调用next(g),并且不需要关心StopIteration的错误。当next(g)不能生成元素了会报StopIteration错误。

    g = (x for x in range(10))
    for n in g:
        print(n)
    

    在较复杂的情况下,无法用迭代完成时,generator可以用函数来实现。比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

    1, 1, 2, 3, 5, 8, 13, 21, 34, ...

    斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            print(b)
            a, b = b, a + b
            n = n + 1
        return 'done'
    

    上面的函数打印了斐波那契数列的前max个数,这里只需要把print(b)修改成yield(b)fib函数就变成了一个generator

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield(b)
            a, b = b, a + b
            n = n + 1
        return 'done'
    

    直接打印fib(4)时,已经不是按照之前的规则输出数列,结束时输出done,而是这样一串字符

    <generator object fib at 0x000001E7F04B8258>
    

    这是因为generator和函数的执行流程不同,函数是顺序执行遇到return或者执行完成就结束了;而generator则是在每次条用next时执行,遇到yield语句返回,再次执行next时从上次的yield继续执行。举个例子:

    def odd():
        print('step 1')
        yield (1)
        print('step 2')
        yield (2)
        print('step 3')
        yield (3)
    
    
    o = odd()
    print(next(o))
    print(next(o))
    print(next(o))
    

    输出结果:

    step 1
    1
    step 2
    2
    step 3
    3 
    

    从输出结果可以看得出来,每调用一次next都会停在yield的地方,下一次执行next有会接着从这里开始。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next(o)就报错。

    同时这里还会发现一个问题,当使用yield将函数变成generator函数是无法获取return的值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中。

    迭代器

    之前提高过迭代的概念,也就是for..in,支持的数据类型有listtupledictsetstr等;generatorgenerator函数也是支持的,这些都是Iterable对象。在迭代中有提到isinstance()函数可以判断一个对象是否是Iterable对象。

    其中generator不仅可以使用for循环并且可以使用next()函数并不断返回下一个值,这样的对象被称为迭代器(Iterator)

    同样可以使用isinstance()函数判断一个对象是否是Iterator对象

    from collections import Iterator
    
    print(isinstance([], Iterator))
    print(isinstance({}, Iterator))
    print(isinstance('', Iterator))
    

    以上上种类型输出的结果都是False

    这里有一点需要注意,generatorIterator,但listdictstr虽然是Iterable,却不是Iterator。使用iter()函数可以将listdictstrIterable变成Iterator

    for循环的本质就是通过不断条用next()函数实现的。

    相关文章

      网友评论

          本文标题:Python高级特性-2

          本文链接:https://www.haomeiwen.com/subject/nwjsmftx.html