一般认为的python解析器如下:
[for i in range(10)]事实上,这只是其中的一种。 解析式这个大概念可以分为以下几种:
列表解析式生成器解析式集合解析式字典解析式如下对一个列表里所有的数值求平方就是列表解析式:
>>> lst = list(range(10)) >>> ret = [] >>> for x in lst: ... ret.append(x ** 2) ... >>> ret [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> >>> ret = [x ** 2 for x in lst] >>> ret [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]通用语法:[expr for e in iterator] 再这个表达式里面我们可以使用我们的元素,这样子的列表解析式和我们的for循环是等价的。
列表解析式的优点:
代码简洁,可读性高效率比普通的迭代稍高,但并不是数据量级上的,只是稍微有一点。如下为带if语句的列表解析
>>> lst = list(range(10)) >>> ret = [] >>> for x in lst: ... if x % 2 == 0: ... ret.append(x) ... >>> ret [0, 2, 4, 6, 8]相当于如下用解析式的方式:
>>> ret = [x for x in lst if x % 2 == 0] >>> ret [0, 2, 4, 6, 8]这种解析式是可以多个if组合的
>>> ret = [x for x in lst if x > 0 if x < 5] >>> ret [1, 2, 3, 4]若表达式里面需要有一个或的关系,可以如下:
>>> ret = [x for x in lst if x < 5 or x > 7 if x % 2 == 0] >>> ret [0, 2, 4, 8]若是想要用and也是一样的。因此:带多个if语句的,都可以转化为常见的逻辑运算,所有一般来说不会带多个if语句。
ret = [x for x in lst if x > 0 if x < 5 if x % 2 == 0] #这两种是等价的。 for x in lst: if (x % 2 == 0) and (x > 0) and (x < 5): ret.append(x)那如果想要用2个元素进行就可以使用元组的形式进行封装
>>> ret = [] >>> for x in range(3): ... for y in range(4,7): ... ret.append((x,y)) ... >>> ret [(0, 4), (0, 5), (0, 6), (1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6)] >>> ret = [(x, y) for x in range(3) for y in range(4,7)] >>> ret [(0, 4), (0, 5), (0, 6), (1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6)]解析式是可以有多个for语句逐层嵌套的
>>> ret = [] >>> for x in range(3): ... if x > 1: ... for y in range(3): ... ret.append((x,y)) ... >>> ret [(2, 0), (2, 1), (2, 2)] #上下两者是等价的 >>> ret = [(x, y) for x in range(3) if x > 1 for y in range(3)] >>> ret [(2, 0), (2, 1), (2, 2)]for里面套if,if里面套for也是可以的
使用列表解析是为了让代码更简洁。但是如果解析式过于繁琐的话还是用for循环比较好。
偶数求平方,奇数求立方:
>>> ret = [] >>> for x in lst: ... if x % 2 == 0: ... ret.append(x ** 2) ... else: ... ret.append(x ** 3) ... >>> ret [0, 1, 4, 27, 16, 125, 36, 343, 64, 729] #等价于: >>> ret = [] >>> if x % 2 == 0: ... ret = x ** 2 ... else: ... ret = x ** 3 ... >>> ret 729语法:x if cond else y
当条件(cond)满足时,返回x当条件不满足时,返回y这种表达式我们称为三元表达式,也称为三目表达式。 用解析式的方式:
>>> ret = [x ** 2 if x % 2 == 0 else x ** 3 for x in lst] >>> ret [0, 1, 4, 27, 16, 125, 36, 343, 64, 729]没有else是不行的,三元表达式只能用双分支
使用生成器解析式可以实现按需取值:
>>> ret = (x ** 2 for x in range(10)) >>> ret <generator object <genexpr> at 0x000002011175FC48> >>> next(ret) 0 >>> next(ret) 1这样就可以通过使用next()的方式获取值。 列表解析中的中括号变成小括号,就称为生成器解析式了 生成器解析式返回的是一个生成器
生成器的优点:
不占内存惰性求值看看表达式什么时候计算的呢?
>>> def fn(x): ... print('executed') ... return x ... >>> g = (fn(x) for x in range(10)) >>> next(g) executed 0 >>> next(g) executed 1如上可知,每次再next调用的时候才会进行计算。 生成器解析式和列表解析式是一摸一样的,只是生成器解析式返回的结果是一个生成器。
生成器都是迭代器生成器是无法用下标访问的因此可知:
我们明确知道需要用下标访问的时候,用列表解析,只需要对结果迭代的时候,无论如何优先使用生成解析器如果我们要用缓存的话,就不能用生成器解析,要用列表解析。所有的操作都和列表解析是一样的,只不过返回的是集合
如上为字典解析,将key和value之间用冒号分隔,其他还是一样的。
解析式这一章由很多我没有接触过的东西,但是也不难理解,看起来复杂还是和前面所学的几种数据结构息息相关。把握好前面的内容也就不难去理解了。
