# Python推导式详解-演道网

Python语言有一种独特的推导式语法，有点像语法糖，可以帮你在某些场合写出比较精简酷炫的代码，同时，它的性能可能会比我们写循环要好。它主要用于初始化一个列表，也可以用于初始化集合和字典。

## 1. 推导式分类与用法

### 1.1 列表推导

>>> [i for i in range(10)]
[0,1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> [i*i for i in range(10)]
[0,1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> l = []
>>> for i in range(10):
...   l.append(i*i)
...
>>>             

m = [[0,0,0],
[0,0,0],
[0,0,0]
]

n = []
for row in range(3):
r = []
for col in range(3):
r.append(0)
n.append(r)
print(n)

>>> [[0]*3 for i in range(3)]
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

#### for循环前面加if…else…

# 如果i是5的倍数，结果是i，否则就是0
>>> [i if i % 5 == 0 else 0 for i in range(20)]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 10, 0, 0, 0, 0, 15, 0, 0, 0, 0]

# 如果是偶数就加100，奇数就减100
>>> [i+100 if i % 2 == 0 else i-100 for i in range(10)]
[100, -99, 102, -97, 104, -95, 106, -93, 108, -91]

#### for循环后面加if…

# for循环的结果只选择是偶数的
>>> [i for i in range(10) if i % 2 == 0]
[0, 2, 4, 6, 8]
# for循环的结果只选择是2和3的倍数的
>>> [i for i in range(10) if i % 2 == 0 and i % 3 == 0]
[0, 6]
# for循环的结果只选择偶数，并且应用str函数
>>> [str(i) for i in range(10) if i % 2 == 0]
['0', '2', '4', '6', '8']

#### 嵌套循环

m = [[1,2,3],
[4,5,6],
[7,8,9]
]

n = []
for row in m:
for col in row:
n.append(col)
print(n)

m = [[1,2,3],
[4,5,6],
[7,8,9]
]
n = [col for row in m for col in row]
print(n)

>>> [a + b for a in '123' for b in 'abc']
['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']

#### 更多用法

>>> dic = {"k1":"v1","k2":"v2"}
>>> a = [k+":"+v for k,v in dic.items()]
>>> a
['k1:v1', 'k2:v2']

### 1.2 集合推导

>>> { i for i in range(10)}
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> { 0 if i % 2 == 0 else 1 for i in range(10)}
{0, 1}

### 1.3 字典推导

>>> { i : i.upper() for i in 'hello world'}
{'h': 'H', 'e': 'E', 'l': 'L', 'o': 'O', ' ': ' ', 'w': 'W', 'r': 'R', 'd': 'D'}
>>> { str(i) : i*i for i in range(10)}
{'0': 0, '1': 1, '2': 4, '3': 9, '4': 16, '5': 25, '6': 36, '7': 49, '8': 64, '9': 81}

### 1.4 元组推导？不存在的

>>> a = (i for i in range(10))
>>> print(a)
<generator object  at 0x000001A6100869C8>
>>> type(a)
<class 'generator'>

>>> a = (i for i in range(0,2))
>>> a[0]
Traceback (most recent call last):
File "", line 1, in
TypeError: 'generator' object is not subscriptable
>>> next(a)
0
>>> next(a)
1
>>> next(a)
Traceback (most recent call last):
File "", line 1, in
StopIteration

>>> a = (i for i in range(0,2))
>>> for i in a:
...   print(i)
...
0
1

>>> a = (i for i in range(0,3))
>>> next(a)
0
>>> for i in a:
...   print(i)
...
1
2

>>> a = tuple(i for i in range(0,3))
>>> a
(0, 1, 2)
>>> a = tuple( (i for i in range(0,3)) )
>>> a
(0, 1, 2)

### 2.1 列表推导式与循环的性能

import timeit

def getlist1():
l = []
for i in range(10000):
l.append(i)
return l

def getlist2():
return [i for i in range(10000)]

# 各执行10000次
t1 = timeit.timeit('getlist1()',"from __main__ import getlist1", number=10000)
t2 = timeit.timeit('getlist2()',"from __main__ import getlist2", number=10000)

print('循环方式：',t1)
print('推导式方式：',t2)

循环方式： 5.343517699991935

getlist1的反编译如下，左边红色对应源代码的行数，蓝色圈内就是第6行代码对应的字节码，我们可以看到，它有一个传参并且调用方法append的过程，调用函数的代价是比较大的。

### 2.2 列表推导式与生成器推导式的性能

import timeit

def getlist1():
return [i for i in range(10000)]

def getlist2():
return (i for i in range(10000))

# 各执行10000次
t1 = timeit.timeit('getlist1()',"from __main__ import getlist1", number=10000)
t2 = timeit.timeit('getlist2()',"from __main__ import getlist2", number=10000)

print('列表：',t1)
print('生成器：',t2)

def getlist11():
a = [i for i in range(10000)]
sum = 0
for i in a:
sum += i

def getlist22():
a = (i for i in range(10000))
sum = 0
for i in a:
sum += i

# 各执行10000次
t1 = timeit.timeit('getlist11()',"from __main__ import getlist11", number=10000)
t2 = timeit.timeit('getlist22()',"from __main__ import getlist22", number=10000)

print('列表：',t1)
print('生成器：',t2)

列表： 2.5977418000111356