# 盘一盘 Python 系列特别篇 - 两大利「器」

1.生成器

1. 使用函数 (function)
2. 使用表达式 (expression)

1.1第一种方法

`def square(nums):    results = []    for num in nums:        results.append(num*num)    return results`

`my_nums = square([1, 2, 3, 4, 5])print(my_nums)`
`[1, 4, 9, 16, 25]`

1. 不要 return (即不需要定义列表 results)
2. 使用 yield (给定一个 num 来 yield 一个 num*num)
`def square(nums):    for num in nums:        yield num*num`

`my_nums = square([1, 2, 3, 4, 5])print(my_nums)`
`<generator object square at 0x00000179D3629ED0>`

`list(my_nums)`
`[1, 4, 9, 16, 25]`

`print(next(my_nums))`
`1`

`print(next(my_nums))print(next(my_nums))print(next(my_nums))print(next(my_nums))`
```4
9
16
25```

`print(next(my_nums))`

```my_nums = square([1, 2, 3, 4, 5])
for num in my_nums:    print(num)```
```1
4
9
16
25```

1.2第二种方法

`my_nums = [x*x for x in [1,2,3,4,5]]print(my_nums)`
`[1, 4, 9, 16, 25]`

`my_nums = (x*x for x in [1,2,3,4,5])print(my_nums)`
`<generator object <genexpr> at 0x00000179D3C4B048>`
`print(list(my_nums))`
`[1, 4, 9, 16, 25]`

1.3生成器 vs 列表

`import timeimport sys`

```%time l = [x+1 for x in range(10000000)]print(sys.getsizeof(l))
%time g = (x+1 for x in range(10000000))print(sys.getsizeof(g))```
```Wall time: 1.28 s
81528056

Wall time: 0 ns
120```

2.迭代器

2.1

`from collections import Iterable`
`print(isinstance([1,2,3], Iterable))    # listprint(isinstance({'1':23}, Iterable))   # dictprint(isinstance((1,2,3), Iterable))    # tupleprint(isinstance({1,2,3}, Iterable))    # setprint(isinstance('123', Iterable))      # strprint(isinstance(123, Iterable))        # intprint(isinstance(123.0, Iterable))      # float`
```True
True
True
True
True
False
False```

`print(dir([1,2,3]))`

`print(dir(123))`

2.2迭代器

`from collections import Iterator`
`print(isinstance([1,2,3], Iterator))    # listprint(isinstance({'1':23}, Iterator))   # dictprint(isinstance((1,2,3), Iterator))    # tupleprint(isinstance({1,2,3}, Iterator))    # setprint(isinstance('123', Iterator))      # str`
```False
False
False
False
False```

`print(isinstance(iter([1,2,3]), Iterator))    # listprint(isinstance(iter({'1':23}), Iterator))   # dictprint(isinstance(iter((1,2,3)), Iterator))    # tupleprint(isinstance(iter({1,2,3}), Iterator))    # setprint(isinstance(iter('123'), Iterator))      # str`
```True
True
True
True
True```

```nums = [1, 2, 3]
for num in nums:    print(num)```
```1
2
3```

`print(next(nums))`

`i_nums = iter(nums)print(i_nums)print(dir(i_nums))`

```i_nums = iter(nums)
print( next(i_nums) )print( next(i_nums) )print( next(i_nums) )```
```1
2
3```

```i_nums = iter(nums)
print( next(i_nums) )print( next(i_nums) )print( next(i_nums) )print( next(i_nums) )```
```1
2
3
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-98-cb9222563d74> in <module>
4 print( next(i_nums) )
5 print( next(i_nums) )
----> 6 print( next(i_nums) )

StopIteration:```

```i_nums = iter(nums)
while True:    try:        print(next(i_nums))    except StopIteration:        break```
```1
2
3```
• 第 1 行：将列表转成迭代器。
• 第 4-5 行：如果程序没报错，打印下一个元素
• 第 6-7 行：如果程序报 StopIteration 错，说明已经遍历结束，用 break 语句跳出。

2.3

`class MyRange:        def __init__(self, start, end):        self.value = start        self.end = end        def __iter__(self):        return self        def __next__(self):        if self.value >= self.end:            raise StopIteration        current = self.value        self.value += 1        return current`
• 第 3-6 行：每个类里都要有 __init__ 来构建对象，参数 start 和 end 分别代表是首尾位置，将 start 赋值给 self.value，将 end 赋值给 self.end。
• 第 7-8 行：因为我们会用 __next__ 来使得 MyRange 是个迭代器，那么 __iter__ 返回它本身就好了。
• 第 10-15 行：第 11-12 行在停止条件时提出 StopIteration 。第 13-14 行是将现有状态的值 self.value 赋给变量 current，将 self.value 前进 1 步。第 15 行返回 current。

```nums = MyRange(1, 5)
for num in nums:    print(num)```
```1
2
3
4```

```nums = MyRange(1, 5)
print(next(nums))print(next(nums))print(next(nums))print(next(nums))```
```1
2
3
4```

`def range_generator(start, end):    current = start    while current < end:        yield current        current += 1`

```nums = range_generator(1, 5)
for num in nums:    print(num)```
```1
2
3
4```

```nums = range_generator(1, 5)
print(next(nums))print(next(nums))print(next(nums))print(next(nums))```
```1
2
3
4```

`def range_generator(start):    current = start    while True        yield current        current += 1`

2.4内置迭代器

`import itertools`
`print(dir(itertools))`

count

`counter = itertools.count()`
`print(next(counter))print(next(counter))print(next(counter))print(next(counter))`
```0
1
2
3```

count() 就像是计数器，不停的往前更新。它可用在给不知道大小的数据标注索引。比如我们在收集交易数据，未来有多少个我们不知道，我们就可以用 count() 来不停更新索引值。

```data = [170.1, 170.8, 171.4, 170.5]
minute_data = zip( itertools.count(), data)print(minute_data)```
`<zip object at 0x00000179D362FC88>`

`print(list(minute_data))`
`[(0, 170.1), (1, 170.8), (2, 171.4), (3, 170.5)]`

data 里面有 4 个点，count() 就返回 4 个值，如果data 里面有 4000000 个点，count() 就返回 4000000 个值。体会到使用 count() 的便利了吗？

```counter = itertools.count(start=5)
print(next(counter))print(next(counter))print(next(counter))print(next(counter))```
```5
6
7
8```
```counter = itertools.count(start=5, step=-2)
print(next(counter))print(next(counter))print(next(counter))print(next(counter))```
```5
3
1
-1```

cycle

```cycle = itertools.cycle(('on','off'))
print(next(cycle))print(next(cycle))print(next(cycle))print(next(cycle))```
```on
off
on
off```

cycle() 作用是循环遍历！

repeat

```repeat = itertools.repeat(2, times=3)
print(next(repeat))print(next(repeat))print(next(repeat))print(next(repeat))```
```2
2
2
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-49-4e464e5eee1b> in <module>
4 print(next(repeat))
5 print(next(repeat))
----> 6 print(next(repeat))

StopIteration:```

repeat() 作用是重复，但是一旦设置 times 参数比如 3，那么不能打印次数不能超过 3，否则会报错。

repeat() 还可以和其他高阶函数一起用，如下列 map 函数。将 pow 操作 (第一个参数) 作用在 [0,1,2,3,4] 上，指数为 2。用 repeat() 好处是重复的次数会跟前面 range(n) 匹配。

`square = map( pow, range(5), itertools.repeat(2) )square`
`<map at 0x179d3724908>`
`list(square)`
`[0, 1, 4, 9, 16]`

combinations & permutations

`letters = ['a', 'b', 'c', 'd']numbers = (1, 2, 3, 4)names = {'Steven', 'Sherry'}`

```results = itertools.combinations(letters, 2)
for items in results:    print(items)```
```('a', 'b')
('a', 'c')
('a', 'd')
('b', 'c')
('b', 'd')
('c', 'd')```

```results = itertools.permutations(letters, 2)
for items in results:    print(items)```
```('a', 'b')
('a', 'c')
('a', 'd')
('b', 'a')
('b', 'c')
('b', 'd')
('c', 'a')
('c', 'b')
('c', 'd')
('d', 'a')
('d', 'b')
('d', 'c')```

product

product() 是穷举出所有情况，本例只从 numbers 里面 4 个元素取出 2 个，不同位置元素可以重复。

```results = itertools.product(numbers, repeat=2)
for items in results:    print(items)```
```(1, 1)
(1, 2)
(1, 3)
(1, 4)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 1)
(3, 2)
(3, 3)
(3, 4)
(4, 1)
(4, 2)
(4, 3)
(4, 4)```

```results = itertools.combinations_with_replacement(numbers, 2)
for items in results:    print(items)```
```(1, 1)
(1, 2)
(1, 3)
(1, 4)
(2, 2)
(2, 3)
(2, 4)
(3, 3)
(3, 4)
(4, 4)```

```results = itertools.combinations(numbers, 2)
for items in results:    print(items)```
```(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)```

chain

```results = itertools.chain(letters, numbers, names)
for items in results:    print(items)```
```a
b
c
d
1
2
3
4
Sherry
Steven```

3.总结

• 字典用来创建映射关系
• 函数用来创建可调用对象
• 生成器用来创建迭代器

Stay Tuned!

0 条评论

• ### 盘一盘如何「体系化」学习 Python 基础知识

将零碎的知识点体系化真的很重要，我把 Python 基础的所有要点都放在一张思维脑图（Xmind 做的）里了。不得不说思维导图真是体系化知识的好工具。

• ### 解读吴恩达新书的全球第一帖 (中)

吴恩达 (之后称大神) 在 2018 年 5 月 23 日北京时间早上 6 点 15 分将《Machine Learning Yearning》一书更新到第 3...

• ### 盘一盘 Python 系列特别篇 - 面向对象编程

在写 Keras (下) 时，发现很多内容都要用到类 (class) 和对象 (object)，因此本文作为 Python 系列的特别篇，主要介绍面向对象编程 ...

• ### Python3 迭代器与生成器

迭代是Python最强大的功能之一，是访问集合元素的一种方式。 迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问，直到所有的元素...

• ### 剑指offer第四天

25.复杂链表的复制 输入一个复杂链表（每个节点中有节点值，以及两个指针，一个指向下一个节点，另一个特殊指针指向任意一个节点），返回结果为复制后复杂链表的hea...

• ### 项目管理——实践入门

项目管理——实践入门 前言： 项目管理的作用对象是项目团队（当然也有项目外部的干系人，本文只针对项目团队），最好的项目管理应该是让团队有清晰统一的目标、亲密无间...

• ### Python学习 ：迭代器&生成器

定义生成器可以使用yield关键词。在Python中，它作为一个关键词，是生成器的标志

• ### python一些常用小技巧

这个方法可以将布尔型的值去掉，例如（False，None，0，“”），它使用 filter() 函数。

• ### Python | 数据挖掘，WordCloud词云配置过程及词频分析

其中WordCloud是词云，jieba是结巴分词工具。 问题：在安装WordCloud过程中，你可能遇到的第一个错误如下。