思维导图导读

Python是一门优雅的编程语言,总是用优美的方法地简化代码、执行高效

一、理解3个概念

1、comprehension

  译作 理解、理解力、(语言学习中的)理解联系(或训练)。根据维基百科解释:在编程语言(不限于Python)中,comprehension是一种语法结构,功能是基于已有的一个数据序列经过“过滤”(满足一定条件)生成一个新的数据序列

  其本质是一种遍历方式,但它执行速度比for循环、map快35-45%。工作方式类似于for循环。

2、Python 可变、不可变

  • 不可变对象,该对象所指向的内存中的值不能被改变当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。
  • 可变对象,该对象所指向的内存中的值可以被改变。变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的出地址,通俗点说就是原地改变

  推导式操作的对象是 可变对象。

3、6种Python标准数据类型

  • 不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);
  • 可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)

  推导式操作的数据对象是 可变数据。

二、详述三种推导式、一种生成器表达式

1、列表推导式(list comprehension,LC)

  将一个列表经过过滤后转换成另一个列表。语法:

  [表达式 for 变量 in 列表]  Or [表达式 for 变量 in 列表 if条件] Or

  [表达式部分 列表生成部分 过滤部分(可选)]  Or [满足条件的元素相关操作 for 元素 in 可迭代数据类型 if 元素相关的条件]

表达式部分:一般是一个表达式作用一个列表的元素;或 只是接受导出的元素,没有表达式;

列表生成部分:一般是一个for循环产生初始列表,并依次导出元素;

过滤部分:一般由一个if判断构成,条件为假的过滤掉。这部分可选。

 

举例1:生成一个由0-9的平方组成的列表

  方案1、用for循环

>>> squares = []
>>> for x in range(10):
...     squares.append(x**2)
... 
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9

  这创建的名为x的变量,在循环结束后仍然存在。可以用“无副作用”的方式生成一个平方值的列表,如下:方案2

>>> squares = list(map(lambda x: x**2, range(10)))
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

  方案3:list comprehesion

>>> squares = [x**2 for x in range(10)]
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x # 也是有“副作用”的
9

其中方案3是最简洁、易读的。列表推导式由括号中的表达式+for子句(甚至嵌套列表推导式,它本质是个列表组成,后边可以跟更多的for循环或if条件(过滤条件),结果是生成一个由表达式、for或if语句运算得出的新列表

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x!=y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

若用for循环来做将是:

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...             if x != y:
...                     combs.append((x,y))
... 
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

这不符合Python优雅气质。

 

举例2:将一个3x4矩阵变成4x3矩阵

>>> matrix = [
...     [1,2,3,4],
...     [5,6,7,8],
...     [9,10,11,12],
... ]
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

如果用for循环完成,将是多少行语句。LC是更简单有效的强力工具。LC总是返回一个结果,无论是否用到它。

2、生成器表达式

将列表推导式的 [] 改成 () 就得到生成器表达式。

生成器中的值只能按顺序调用一次,只能向前,不能后退。其工作方式是每次处理一个对象,而不是一次性处理和构造整个数据结构,优点是可以节省大量内存。因此,在处理大量数据时,建议使用生成器表达式,而不是列表推导式。生成器表达式结构:

生成器=(返回结构 执行对象 if 判断条件)

举例:得到30以内能被3整除的数。

>>> multiples = (i for i in range(30) if i%3 is 0)
>>> multiples
<generator object <genexpr> at 0x7f2506c4d9b0>
>>> type(multiples)
<type 'generator'>
>>> for i in multiples:
...     print(i)
... 
0
3
6
9
12
15
18
21
24
27

3、字典推导式

字典推导式,跟列表推导式的使用方法是类似的。只是将中括号[] 改成了 花括号{}。

举例:快速更换key、value。

>>> d = {'a':1, 'b':2}
>>> d = {v:k for k,v in d.items()}
>>> d
{1: 'a', 2: 'b'}

4、集合推导式

集合推导式,跟列表推导式也是类似的。唯一的区别是使用花括号。

集合自带去重功能,如果计算得出的元素有重复值,在集合中一个值只会录入一个元素。

>>> s = {1,2,3,4,5,6}
>>> s = {i**2 for i in s if i%2==0}
>>> print(s)
set([16, 36, 4])

 

总结,这些推导式语法结构上的高度相似的、可举一反三,代码简洁、优雅、高效。

 

参考:官方文档-List Comprehensions

posted on 2018-11-20 16:30  陈校长  阅读(260)  评论(0编辑  收藏  举报