• 09-02解析式


    解析式

    举例场景:对一个列表所有的数值求平方

    • 普通用法
    In [15]: ret = []
        ...: for x in range(10):
        ...:     ret.append(x ** 2)
        ...: print(ret)
        ...:     
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
    • 解析式用法
    In [12]: [x ** 2 for x in list(range(10))]
    Out[12]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    结论:解析式是比普通语句写法:性能更高,代码更简洁、可读性更强的一种表达式。如果用起来就有如上优点、如果不用也可以用更麻烦的方式实现

    解析式与普通用法法的性能及优势

    • 列表解析的效率要高于普通用法
    • 列表解析的代码更简洁、可读性强
    例:列表解析与普通用法法的性能及优势
        In [21]: import timeit
    
        In [22]: %%timeit
            ...: ret = [ x ** 2 for x in range(10)]
            ...: 
        100000 loops, best of 3: 3.5 µs per loop
    
        In [23]: %%timeit
            ...: ret = []
            ...: for x in range(10):
            ...:     ret.append(x ** 2)
            ...: 
        100000 loops, best of 3: 3.88 µs per loop
    
        总结:
            列表解析的效率要高于普通用法
            列表解析的代码更简洁、可读性强
    

    解析式有如下几种

    • 列表解析:[expr for e in iterator]
    • 生成器解析:(expr for e in iterator)
    • 集合解析:{expr for e in iterator}
    • 字典解析:{keys: expr for e in iterator}

    它们都支持:

    • 带if字句的列表解析:[expr for e in iterator if cond]
      • 带单个if的列表解析:[expr for e in iterator if cond]
      • 带任意多个的if字句:[ x for x in range(10) if x > 0 if x < 5 if x % 2 == 0]

    列表解析

    列表解析返回的都是列表,输入对象是所有可迭代对象。

    • 带if字句的列表解析:[expr for e in iterator if cond]
      • 带单个if的列表解析:[expr for e in iterator if cond]
      • 带任意多个的if字句:[ x for x in range(10) if x > 0 if x < 5 if x % 2 == 0]
    • 带for语句的列表解析
      • 带单个for的列表解析
      • 带多个for的列表解析
    • 带if和for的列表解析
      • 带单个if和for的列表解析
      • 带多个if和for的列表解析
    • 嵌套解析式(不建议使用)

    带if字句的列表解析

    解析式:[expr for e in iterator if cond]

    例:带单个if的列表解析
    In [25]: ret = []
        ...: for x in range(10):
        ...:     if x % 2 == 0:
        ...:         ret.append(x)
        ...: print(ret)
        ...:
    [0, 2, 4, 6, 8]
    
    In [26]: [x for x in range(10) if x % 2 == 0]
    Out[26]: [0, 2, 4, 6, 8]
    
    
    例:带任意多个的if字句
    In [27]: [ x for x in range(10) if x > 0 if x < 5 if x % 2 == 0]
    Out[27]: [2, 4]
    
        带多个if语句的, 都可以转换为条件的逻辑运算, 所以一般来说, 不会带多个if语句。
    

    带for语句的列表解析

    例:可以有多个for语句, 相当于逐层嵌套
    In [30]: [(x, y) for x in range(3) for y in range(5, 8)]
    Out[30]: [(0, 5), (0, 6), (0, 7), (1, 5), (1, 6), (1, 7), (2, 5), (2, 6), (2, 7)]
    
    In [32]: [(x, y, z) for x in range(2) for y in range(5, 7) for z in range(10, 12)]
    Out[32]: 
    [(0, 5, 10),
     (0, 5, 11),
     (0, 6, 10),
     (0, 6, 11),
     (1, 5, 10),
     (1, 5, 11),
     (1, 6, 10),
     (1, 6, 11)]
    

    带多个if语句和for语句

    例:多个for语句及if语句
    In [33]: [(x, y) for x in range(3) if x > 0 for y in range(5, 8)]
    Out[33]: [(1, 5), (1, 6), (1, 7), (2, 5), (2, 6), (2, 7)]
    

    嵌套的列表解析

    例:嵌套的列表解析
    In [11]: [ x for x in [y for y in range(10)]]
    Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    难以预测结果, 所以一般不用

    使用列表解析为了让代码更简洁
    什么时候用代码解析式, 什么时候不用代码解析式, 跟着感觉走。什么时候不用代码解析式能简洁代码就什么时候不用。
    能一下子看出输出结果时, 就用, 如果一眼看不出结果的解析式的结果就不要用了。

    偶数求平方, 奇数求立方

    例:偶数求平方, 奇数求立方
        普通用法:
        In [36]: ret = []
            ...: for x in range(10):
            ...:     if x % 2 == 0:
            ...:         ret.append(x ** 2)
            ...:     else:
            ...:         ret.append(x ** 3)
            ...: print(ret)
            ...:
        [0, 1, 4, 27, 16, 125, 36, 343, 64, 729]
    
        列表解析式用法
        In [37]: [ x ** 2 if x % 2 == 0 else x ** 3 for x in range(10) ]
        Out[37]: [0, 1, 4, 27, 16, 125, 36, 343, 64, 729]
    
        列表解析的表达式
        In [3]: x = 3
    
        In [4]: x ** 2 if x % 2 == 0 else x ** 3
        Out[4]: 27
    
        x if cond else y  # 当条件满足时返回x, 当条件不满足时返回y
    
        In [15]: x ** 2 if x % 2 == 0 else x ** 3
        Out[15]: 27
    
    python 2.7 已经支持表达解析式
    列表解析得到的结果是列表, 输入对象是所有可迭代对象。
    

    生成器解析

    生成器是什么:生成器是一次生成一个值的特殊类型函数。

    Python3 迭代器与生成器
    在 Python 中,使用了 yield 的函数被称为生成器(generator)。
    跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
    在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
    调用一个生成器函数,返回的是一个迭代器对象。

    • 列表解析的中括号变成小括号就是生成器解析了
    • 生成器解析比列表解析的优势在于,当要生成的数特别大时列表解析会占用非常大的内存,而生成器解析不用
    • 什么时候用列表解析, 什么时候用生成器解析?
      • 需要用下标访问的时候, 用列表解析, 只需要对结果迭代的时候, 优先使用生成器解析。
    例:生成器解析与列表解析的区别
    In [16]: range(10000)    # 当要生成的数特别大时
    Out[16]: range(0, 10000)
    
    In [17]: [ x ** 2 for x in range(10000)]  # 会占用很多内存
    
    In [18]: (x ** 2 for x in range(10000))
    Out[18]: <generator object <genexpr> at 0x7fb8f0ed8f68>   # 返回一个generator, 并且没有占用多少内存。
    
    In [19]: type((x ** 2 for x in range(10000)))
    Out[19]: generator
    
    In [20]: g = (x ** 2 for x in range(10000))
    
    In [21]: next(g)   # 生成器解析调用的方法
    Out[21]: 0
    
    In [22]: next(g)
    Out[22]: 1
    
    总结:
        列表解析的中括号变成小括号就是生成器解析了
        生成器解析式返回的是一个生成器
    
    
    例:表达式在取值的时候才开始计算
    In [23]: def fn(x):
        ...:     print('executed')
        ...:     return x
        ...: 
    
    In [24]: g = (fn(x) for x in range(10))
    
    In [25]: next(g)
    executed
    Out[25]: 0
    
    In [26]: next(g)
    executed
    Out[26]: 1
    
    In [27]: next(g)
    executed
    Out[27]: 2
    
    什么时候用列表解析, 什么时候用生成器解析?
        需要用下标访问的时候, 用列表解析, 只需要对结果迭代的时候, 优先使用生成器解析。
    

    集合解析

    • 集合解析返回的是集合
    • 集合解析式用大括号
    In [1]: {x for x in range(10)}
    Out[1]: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    
    In [2]: s = {x for x in range(10)}
    
    In [3]: type(s)
    Out[3]: set
    
    总结:
        集合解析返回的是集合
        集合解析式用大括号
    

    字典解析

    • 字典解析式:key的表达式和value的表达式组成
    例:字典解析表达
    In [4]: {str(x): x for x in range(10)}
    Out[4]: 
    {'0': 0,
     '1': 1,
     '2': 2,
     '3': 3,
     '4': 4,
     '5': 5,
     '6': 6,
     '7': 7,
     '8': 8,
     '9': 9}
    
    {str(x): x for x in range(10)}    # : 冒号之前是key的表达式, 冒号之后的是value的表达式
    
    例:普通表达式
    In [8]: d = {}
       ...: for x in range(10):
       ...:     d[str(x)] = x
       ...:     
    
    In [9]: d
    Out[9]: 
    {'0': 0,
     '1': 1,
     '2': 2,
     '3': 3,
     '4': 4,
     '5': 5,
     '6': 6,
     '7': 7,
     '8': 8,
     '9': 9}
    
    例:字典解析
    In [82]: {x:y for y, x in {'1': '2', '3': '4'}.items()}
    Out[82]: {'2': '1', '4': '3'}
    
    
    字典解析式:key的表达式和value的表达式组成
    
  • 相关阅读:
    记录JavaScript原型和原型链复习笔记
    记录浏览器渲染流程解析
    记录前端路由 hash 与 history 差异
    作用域&变量提升&闭包题目及内容解答
    记录JS原型链
    记录JS精粹,原型链继承和构造函数继承的 “毛病”
    虚拟DOM的理解与总结
    Vite+TS项目:论如何便捷的使用pinia
    Redis知识总结
    JVM家庭成员盘点及各自职能介绍 https://mp.weixin.qq.com/s/TkGZ5fMTOdr9ABNf_xllnw
  • 原文地址:https://www.cnblogs.com/cishi/p/13041264.html
Copyright © 2020-2023  润新知