• day18-列表生成式、迭代器


    1、列表生成式,也叫列表推导式

    即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
    优点:构造简单,一行完成
    缺点:不能排错,不能构建复杂的数据结构

    1.1、循环模式[i for i in iterable]

     l1 = [i for i in range(1,101)]
     print(l1)

    l2 = ['python第%s天'%i for i in range(1,11)]
    print(l3)
    结果:
    [
    'python第1天', 'python第2天', 'python第3天', 'python第4天', 'python第5天', 'python第6天', 'python第7天', 'python第8天', 'python第9天', 'python第10天']

    10以内的数的平方

    l3 = [i*i for i in range(11)]
    print(l3)
    结果:
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    1.2、筛选模式[i for i in iterable if 判断式]

    a = [i for i in range(1,100) if i%2==1]
    print(list(a))或print(a)
    结果:
    [
    1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]

    或一句话输出

    print([i for i in range(1,100) if i%2==0])
    结果:
    [
    2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]

    30以内能被3整除的数的平方

    l4 = [i*i for i in range(31) if i%3 == 0]
    print(l4)
    结果:
    [0,
    9, 36, 81, 144, 225, 324, 441, 576, 729, 900]#

    过滤掉非字符串类型和长度小于3的字符串,并将剩下的转成大写字母

    lst = ['mike', 'tom', 'jack', 're', 'ab', 123]
    l5 = [i.upper() for i in lst if isinstance(i, str) and len(i) >= 3]
    print(l5)
    结果:
    ['MIKE', 'TOM', 'JACK']

    列出当前目录下的所有文件和目录名,可以通过一行代码实现:

    import os 
    print([d for d in os.listdir('.')]) # os.listdir可以列出文件和目录
    ['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']

    3、两层循环,可以生成全排列

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

    列表生成式也可以使用两个变量来生成list:

    d = {'x': 'A', 'y': 'B', 'z': 'C' }
    print([k + '=' + v for k, v in d.items()])
    ['y=B', 'x=A', 'z=C']

    一句话生成九九乘法表

    print ('
    '.join([' '.join(['%s*%s=%-3s'%(y,x,x*y) for y in range(1,x+1)]) for x in range(1,10)]))

    2、迭代器

    1、可迭代对象

    内部含有'__iter__'方法的数据就是可迭代对象
    可迭代对象:list、str、tuple、set、dict、range()、文件句柄

    print(dir(对象名))
    如果打印结果里面有'__iter__',则这个对象就是可迭代对象

    print('__iter__' in dir([1,2,3]))
    True
    如果结果为True,就表示对象是可迭代对象

    2、迭代器
    内部含有'__iter__'方法,并且含有'__next__'方法的对象就是迭代器
    文件句柄就是一个迭代器

    f1 = open('1.txt', encoding='utf-8'):
    print('__iter__' in dir(f1))
    True
    print('__next__' in dir(f1))
    True
    l1 = [1,2,3,'a']
    iter1 = iter(l1)
    或
    iter1 = l1.__iter__()
    
    print(iter1.__next__())
    print(iter1.__next__())
    print(iter1.__next__())
    print(iter1.__next__())
    
    1
    2
    3
    a
    #迭代完了之后如果再取值,就会报错StopIteration

    迭代器特点:
    1、非常节省内存
    2、满足惰性机制
    3、一条路走到黑

    利用while循环模拟for循环
    1、将可迭代对象转化成迭代器
    2、利用next进行取值
    3、利用异常处理终止循环

    l1 = [1,2,3,'a']
    iter1 = l1.__iter__()
    while 1:
        try:
            print(iter1.__next__())
        except StopIteration:
            break

    3、生成器,自己用python代码写的迭代器

            通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
            所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    有两种方式:

    1、函数式写法
    2、生成器表达式

    函数式写法,构建生成器
    只要函数中出现yield,那么他就不是一个函数了,他是生成器函数

    def func1():
        yield 3
        yield 4
    func1()  #这样不会调用该函数
    
    g = func1()
    print(g.__next__()) #一个next对应一个yield的值
    print(g.__next__()) #再一个next对应下一个yield的值
    
    3
    4

    yield和return的区别

    return 结束函数,给函数返回值
    yield不会结束生成器函数,一个next对应一个yield进行取值

    例子:如果循环打印一个列表,可以同时打印出来

    def num1():
        for i in range(1,11):
            print('编号%s'%(i))
    num1()
    
    
    编号1
    编号2
    编号3
    编号4
    编号5
    编号6
    编号7
    编号8
    编号9
    编号10

    也可以不一次性打印出来,需要打印几个就先打印出几个

    def num2():
        for i in range(1,11):
            yield ('编号%s'%(i))
    g = num2() #这里需要将函数执行重新赋值给一个变量,不能用print(num2().__next__(),否则每次打印都是第一个值1
    print(g.__next__())
    #编号1
    for i in range(3):
        print(g.__next__())
    #编号2
    #编号3
    #编号4
    for i in range(6):
        print(g.__next__())
    #编号5
    #编号6
    #编号7
    #编号8
    #编号9
    #编号10

    4、生成器表达式

    只需要将列表推导式用小括号表示即可生成一个生成器迭代器

    g1 = (i*i for i in range(10000))
    print(g1.__next__())
    print(g1.__next__())
    print(g1.__next__())
    print(g1.__next__())
    print(g1.__next__())
    0
    1
    4
    9

    如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
    比如,著名的斐波拉契数列(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+=1
    
    fib(6)
    1
    1
    2
    3
    5
    8
    13

    仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
    也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n = n + 1
        print('done')
    g = fib(6)
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    1
    1
    2
    3
    5

    把函数改成generator后,如果用next()来获取下一个返回值有点麻烦,也可以直接使用for循环来迭代:

    for n in fib(6):
        print(n)
    1
    1
    2
    3
    5
    8

    例子:

    杨辉三角定义如下:

         1
             1 1
            1 2 1
          1 3 3 1
        1 4 6 4 1
    1 5 10 10 5 1

    把每一行看做一个list,试写一个generator,不断输出下一行的list:
    def triangel(max):
        n,L=0,[1]               #定义一个list[1]
        while n<max:
            yield L             #打印出该list
            L=[1]+[L[x]+L[x+1] for x in range(len(L)-1)]+L[1] #计算下一行中间的值,两边再各添加一个[1]
    
    #生成一个generator对象,然后通过for循环迭代输出每一行
    a=triangel(10)
    for i in a:
        print(i)

    或者

    def triangles(max):
        L=[1]
        i = 0
        while n<max:
            yield L                                  
            L.append(0)
            L = [L[i-1]+L[i] for i in range(len(L))]
    
    a=triangel(10)
    for i in a:
        print(i)

    注:普通函数和generator生成器的区别:
    1.普通函数调用直接返回结果,generator函数的调用,返回一个generator对象;
    (调用generator时可以先创建一个对象,再用next()方法不断获得下一个返回值,但实际中通常用for循环实现)
    2.generator在执行过程中,遇到yield就中断,下次又继续执行

  • 相关阅读:
    C#动态生成Word文档并填充数据
    解析C#中is和as操作符的用法
    转载opencv2.4.0在Vs10下的配置
    XNA之RPG游戏开发教程之一
    XNA之RPG游戏开发教程之四
    XNA之RPG游戏开发教程之二
    有关BackgroundWork类的使用
    XNA之RPG游戏开发教程之六
    XNA之RPG游戏开发教程之八
    XNA之RGP游戏开发教程之七
  • 原文地址:https://www.cnblogs.com/dxnui119/p/9910150.html
Copyright © 2020-2023  润新知