集合表达式是Python强大的功能之一,每个Python必须学习基本功。
List推导式(List Comprehension)
快速创建List集合
>>> [x * x for x in range(10)] # List comprehension: builds list
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # Like list(generator expr)
>>> [x for x in range(5) if x % 2 == 0]
[0, 2, 4]
>>> list(filter((lambda x: x % 2 == 0), range(5)))
[0, 2, 4]
>>> res = []
>>> for x in range(5):
if x % 2 == 0:
res.append(x)
>>> res
[0, 2, 4]
list comprehension相比于lambda和for循环都要简单的多。
>>> res = [x + y for x in [0, 1, 2] for y in [100, 200, 300]]
>>> res
[100, 200, 300, 101, 201, 301, 102, 202, 302]
list comprehension中可以嵌套多个for语句,相当于嵌套的for循环一样。
Set推导式(Set Comprehension)
快速创建不含重复元素的Set集合
>>> {x * x for x in range(10)} # Set comprehension, 3.X and 2.7
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36} # {x, y} is a set in these versions too
用法和List Comprehension类似。
Dictionary推导式(Dictionary Comprehension)
快速创建Dictionary集合,类似于java中的Map。
>>> {x: x * x for x in range(10)} # Dictionary comprehension, 3.X and 2.7
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
用法和List Comprehension类似。
生成表达式(Generator Expression)
生成表达式相对于推导式来说复杂一些,这里会慢慢道来。
首先看一下生成表达式和生成函数:
>>> (x * x for x in range(4))
>>> def gensquares():
for x in range(4):
yield x * x
这个表达式和函数的作用是一样的,只是生成表达式是生成函数的简写形式,或者说是简单形式。想要了解清楚生成表达式,先要理解生成函数。而生成函数和一般的函数基本一样,主要是多了一个关键字yield,类似普通函数中的return语句,但是yield语句不会立即返回结果,而是在需要的时候调用next方法(或内部的_next_方法)获取结果,类似java中的迭代器Iterable。
>>> f = gensquares()
>>> next(f)
0
>>> next(f)
1
>>> next(f)
4
>>> next(f)
9
>>> next(f)
Traceback (most recent call last):
File "<pyshell#94>", line 1, in <module>
next(f)
StopIteration
>>>
有2点需要注意的:
- 生成器对象只能迭代一次,也就说只能顺序访问一次。
- 当生成对象访问完了之后再次访问会抛出StopIteration异常。
综上所述,生成表达式对于大数据量的集合迭代操作有天生的性能优势,因为每次迭代只是计算部分数据。
yield也可以在一个方法的多个地方使用:
>>> def both():
for i in range(2): yield i
for i in (x**2 for x in range(2)): yield i
>>> f = both()
>>> next(f)
0
>>> next(f)
1
>>> next(f)
0
>>> next(f)
1
>>> next(f)
Traceback (most recent call last):
File "<pyshell#102>", line 1, in <module>
next(f)
StopIteration
>>>
yield from的用法
>>> def both():
yield from range(2)
yield from (x**2 for x in range(2))
这个方法和上一个例子中的方法是一样的,只不过是一种简单的写法而已。
send方法
>>> def gen():
for i in range(10):
X = yield i
print(X)
>>> G = gen()
>>> next(G) # Must call next() first, to start generator
0
>>> G.send(77) # Advance, and send value to yield expression
77
1
>>> G.send(88)
88
2
>>> next(G) # next() and X.__next__() send None
None
3
send(a)方法会将a传递给方法中的X (yield的返回值),并触发下一次迭代,这样send方法可以给下次迭代增加一些业务处理。没有send方法调用的情况下,yield表达式返回None。