├── .gitignore ├── README.md ├── SREADME.md ├── SUMMARY.md ├── images ├── consumers_pipeline.png ├── coroutine_pipeline.png ├── python_linux.png ├── python_macos.png ├── python_windows.jpg ├── python_windows2.jpg ├── python_windows3.jpg └── python_windows4.jpg ├── metadata.yaml └── 章节 ├── 列表.md ├── 协程.md ├── 基础数据类型.md ├── 字典.md ├── 安装.md ├── 异步.md ├── 模块和函数.md ├── 生成器.md ├── 简介.md ├── 类.md ├── 迭代与循环.md └── 迭代器.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Full-speed-python 的个人翻译版本 3 | 原书地址:https://github.com/joaoventura/full-speed-python 4 | 5 | 6 | 进入GitBook在线阅读:[GitBook](https://hubertroy.gitbooks.io/full-speed-python-chinese/content/) 7 | 8 | 进入Love2io在线阅读:[Love2io](https://love2.io/@hubertroy/doc/full-speed-python-chinese) 9 | 10 | # 目录 11 | * 简介 12 | * 安装 13 | * 基础数据类型 14 | * 列表 15 | * 函数 16 | * 循环 17 | * 字典 18 | * 类 19 | * 迭代器 20 | * 生成器 21 | * 协程 22 | * 异步 -------------------------------------------------------------------------------- /SREADME.md: -------------------------------------------------------------------------------- 1 | 2 | 偶然发现的一篇Python的教程,内容从基础的下载安装到异步协程都有涵盖。 3 | 每节又配有几个小习题供练手,觉得十分不错,随手翻译下来~。 4 | 5 | 有错误烦请移步至[GitHub](https://github.com/HuberTRoy/full-speed-python-chinese/issues)发起[Issue](https://github.com/HuberTRoy/full-speed-python-chinese/issues)。 6 | 7 | 感谢~。 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [前言](SREADME.md) 4 | * [简介](章节/简介.md) 5 | * [安装](章节/安装.md) 6 | * [基础数据类型](章节/基础数据类型.md) 7 | * [数字和字符串](章节/基础数据类型.md#数字和字符串) 8 | * [列表](章节/列表.md) 9 | * [列表](章节/列表.md#列表) 10 | * [列表推导式](章节/列表.md#列表推导式) 11 | * [模块和函数](章节/模块和函数.md) 12 | * [模块和函数](章节/模块和函数.md#模块和函数) 13 | * [递归函数](章节/模块和函数.md#递归函数) 14 | * [迭代与循环](章节/迭代与循环.md) 15 | * [字典](章节/字典.md) 16 | * [类](章节/类.md) 17 | * [类](章节/类.md#类) 18 | * [类继承](章节/类.md#类继承) 19 | * [迭代器](章节/迭代器.md) 20 | * [生成器](章节/生成器.md) 21 | * [协程](章节/协程.md) 22 | * [协程](章节/协程.md#协程) 23 | * [管道](章节/协程.md#管道) 24 | * [异步编程](章节/异步.md) 25 | 26 | -------------------------------------------------------------------------------- /images/consumers_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuberTRoy/full-speed-python-chinese/161ec8d8baa4a5b506c811d2ebed866a0b330566/images/consumers_pipeline.png -------------------------------------------------------------------------------- /images/coroutine_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuberTRoy/full-speed-python-chinese/161ec8d8baa4a5b506c811d2ebed866a0b330566/images/coroutine_pipeline.png -------------------------------------------------------------------------------- /images/python_linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuberTRoy/full-speed-python-chinese/161ec8d8baa4a5b506c811d2ebed866a0b330566/images/python_linux.png -------------------------------------------------------------------------------- /images/python_macos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuberTRoy/full-speed-python-chinese/161ec8d8baa4a5b506c811d2ebed866a0b330566/images/python_macos.png -------------------------------------------------------------------------------- /images/python_windows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuberTRoy/full-speed-python-chinese/161ec8d8baa4a5b506c811d2ebed866a0b330566/images/python_windows.jpg -------------------------------------------------------------------------------- /images/python_windows2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuberTRoy/full-speed-python-chinese/161ec8d8baa4a5b506c811d2ebed866a0b330566/images/python_windows2.jpg -------------------------------------------------------------------------------- /images/python_windows3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuberTRoy/full-speed-python-chinese/161ec8d8baa4a5b506c811d2ebed866a0b330566/images/python_windows3.jpg -------------------------------------------------------------------------------- /images/python_windows4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuberTRoy/full-speed-python-chinese/161ec8d8baa4a5b506c811d2ebed866a0b330566/images/python_windows4.jpg -------------------------------------------------------------------------------- /metadata.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | title: 进击的Python 3 | subtitle: Full Speed Python 4 | author: João Ventura 5 | translator: cyrbuzz 6 | 7 | documentclass: book 8 | fontsize: 12pt 9 | --- -------------------------------------------------------------------------------- /章节/列表.md: -------------------------------------------------------------------------------- 1 | # 列表 2 | 3 | Python中的列表是一个可存放一组元素的数据结构。列表中的元素可以是多种类型,你可以在同一个列表中混用多种类型,尽管一般来说里面存放的应该都是同一种数据类型。 4 | 5 | 创建一个列表使用方括号来完成,每个元素中间使用逗号隔开。列表中的元素可以使用它们位置信息(下标)来访问,0是第一个。 6 | ``` 7 | >>> l = [1, 2, 3, 4, 5] 8 | >>> l[0] 9 | 1 10 | >>> l[1] 11 | 2 12 | ``` 13 | 你能试着获取出数字4吗? 14 | 15 | 有时你想要的是列表中的一小段,一个子列表。子列表可以使用一种叫**切片**的方式获取到,使用**切片**需要同时定义开始和结束的索引。 16 | ``` 17 | >>> l = ['a', 'b', 'c', 'd', 'e'] 18 | >>> l[1:3] 19 | ['b', 'c'] 20 | ``` 21 | 最后,列表同样支持算术操作,像是将两个列表合并到一起或者重复其中的元素。 22 | ``` 23 | >>> [1,2] + [3,4] 24 | [1, 2, 3, 4] 25 | >>> [1,2] * 2 26 | [1, 2, 1, 2] 27 | ``` 28 | 29 | ## 列表部分练习 30 | 31 | 创建一个变量`I`,并输入以下值:([1, 4, 9, 10, 23])。 32 | 查阅Python文档(https://docs.python.org/3.5/tutorial/introduction.html#lists) 中关于列表的部分来完成以下练习: 33 | 34 | 1. 使用列表切片获取出子列表`[4, 9]`和`[10, 23]`。 35 | 2. 将`90`添加到列表`I`的末尾。尝试找一下合并两个列表和使用**append**方法有什么不同。 36 | 3. 计算出列表中所有元素的平均数。你可以使用**sum**和**len**两个函数来完成。 37 | 4. 删除子列表`[4, 9]`。 38 | 39 | ## 列表推导式 40 | 列表推导式是一种生成列表的简洁方式。在方括号中写入一个包含**for**关键字的表达式即可完成。生成的内容与表达式有关。 41 | 下面演示了以一个列表中的数生成另一个内容为其数字平方的列表的推导式。 42 | ``` 43 | >>> [x*x for x in [0, 1, 2, 3]] 44 | [0, 1, 4, 9] 45 | ``` 46 | 出于灵活性考虑,列表推导式一般与**range**函数连用: 47 | ``` 48 | >>> [x*x for x in range(4)] 49 | [0, 1, 4, 9] 50 | ``` 51 | 有时你想基于给定条件过滤一些元素。这时**if**关键字就上场了: 52 | ``` 53 | >>> [x for x in range(10) if x % 2 == 0] 54 | [0, 2, 4, 6, 8] 55 | ``` 56 | 上面的例子返回0-10中所有的双数。更多的例子请参阅 https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions 57 | 58 | ## 列表推导式部分练习 59 | 60 | 1. 使用列表推导式创建一个包含前10个数的平方的列表。 61 | 2. 使用列表推导式创建一个包含前20个数的立方的列表。 62 | 3. 使用列表推导式创建一个包含0-20间所有偶数的列表,创建另一个包含其中所有的奇数。 63 | 4. 创建一个内容为0-20间所有偶数的平方的列表,使用**sum**函数将它们相加。结果应该是1140。 64 | 5. 创建一个内容为0-20间所有偶数的平方,但忽略其中可以被3整除的数的列表。换句话说就是可以被2整除但不能被3整除。 65 | 66 | 请参阅Python文档中关于**and**关键字的用法。返回的列表应该是`[4, 16, 64, 100, 196, 256]`。 67 | 68 | -------------------------------------------------------------------------------- /章节/协程.md: -------------------------------------------------------------------------------- 1 | # 协程 2 | 3 | Python的协程很像生成器,但并不是生成数据,大多数时候扮演了数据消费者的作用。换句话说,协程是一个在每次使用send方法发送数据后就会被唤醒的函数。 4 | 5 | 协程的要点是将“yield”关键字写在表达式的右边。下面是一个打印出所发送的值的协程例子: 6 | ``` 7 | def coroutine(): 8 | print('My coroutine') 9 | while True: 10 | val = yield 11 | print('Got', val) 12 | >>> co = coroutine() 13 | >>> next(co) 14 | My coroutine 15 | >>> co.send(1) 16 | Got 1 17 | >>> co.send(2) 18 | Got 2 19 | >>> co.send(3) 20 | Got 3 21 | ``` 22 | 23 | 首先要调用“next”来将协程推进。你可以看到它执行了一个打印。最终,函数进行到“yield”表达式了,然后就会等待唤醒。之后,每次有值被发送过来,协程就会从“yield”处唤醒,将值复制给val并打印出它。 24 | 使用`close()`方法可以关闭这个协程。 25 | ``` 26 | >>> co.close() 27 | >>> co.send(4) 28 | Traceback (most recent call last): 29 | File "", line 1, in 30 | StopIteration 31 | ``` 32 | 33 | ## 协程部分练习 34 | 35 | 1. 创建一个名为“square”的协程,它会打印出所发送的值的平方。 36 | 2. 创建一个名为“minimize”的协程,它会保存并打印出所发送的值中最小的一个值。 37 | 38 | ## 管道 39 | 40 | 协程可以用在部署数据管道中,其中一个协程会发送数据到下一个在数据管道中的协程。协程使用`send()`方法来将数据压入管道。 41 | 42 | ![coroutine_pipeline](../images/coroutine_pipeline.png) 43 | 44 | 下面的例子实现了一个小型管道,值会从生产者协程发送到消费者协程打印出来: 45 | ``` 46 | def producer(consumer): 47 | print("Producer ready") 48 | while True: 49 | val = yield 50 | consumer.send(val * val) 51 | 52 | 53 | def consumer(): 54 | print("Consumer ready") 55 | while True: 56 | val = yield 57 | print('Consumer got', val) 58 | ``` 59 | 如前所述,在发送任何数据前都别忘了调用一次“next”。 60 | ``` 61 | >>> cons = consumer() 62 | >>> prod = producer(cons) 63 | >>> next(prod) 64 | Producer ready 65 | >>> next(cons) 66 | Consumer ready 67 | >>> prod.send(1) 68 | Consumer got 1 69 | >>> prod.send(2) 70 | Consumer got 4 71 | >>> prod.send(3) 72 | Consumer got 9 73 | ``` 74 | 75 | 同样的,对于协程来说,数据可以被发送到不同的地方。下面的例子部署了两个消费者,第一个它只会打印0-10之间的内容,第二个则是10-20。 76 | ``` 77 | def producer(consumers): 78 | print("Producer ready") 79 | try: 80 | while True: 81 | val = yield 82 | for consumer in consumers: 83 | consumer.send(val * val) 84 | except GeneratorExit: 85 | for consumer in consumers: 86 | consumer.close() 87 | 88 | 89 | def consumer(name, low, high): 90 | print("%s ready" % name) 91 | try: 92 | while True: 93 | val = yield 94 | if low < val < high: 95 | print('%s got' % name, val) 96 | except GeneratorExit: 97 | print("%s closed" % name) 98 | ``` 99 | 不要忘了调用下“next”呦。 100 | ``` 101 | >>> con1 = consumer('Consumer 1', 00, 10) 102 | >>> con2 = consumer('Consumer 2', 10, 20) 103 | >>> prod = producer([con1, con2]) 104 | >>> next(prod) 105 | Producer ready 106 | >>> next(con1) 107 | Consumer 1 ready 108 | >>> next(con2) 109 | Consumer 2 ready 110 | >>> prod.send(1) 111 | Consumer 1 got 1 112 | >>> prod.send(2) 113 | Consumer 1 got 4 114 | >>> prod.send(3) 115 | Consumer 1 got 9 116 | >>> prod.send(4) 117 | Consumer 2 got 16 118 | >>> prod.close() 119 | Consumer 1 closed 120 | Consumer 2 closed 121 | ``` 122 | 数据被发送到所有的消费者中,但只有第二个执行了打印命令。注意这里使用的“GeneratorExit”异常。一般都会用捕获异常的方式来通知下游协程这个管道没有用了,赶紧关闭了吧。 123 | 124 | 125 | ![consumers_pipline](../images/consumers_pipeline.png) 126 | 127 | 128 | ## 协程部分练习 129 | 130 | 1. 部署一个生产者-消费者管道,生产者会将值的平方发送给两个消费者。其中一个会储存并打印出所发送的值中最小的一个,另一个则是最大的一个。 131 | 132 | 2. 部署一个生产者-消费者管道,生产者会将值的平方发送给两个消费者,一次只发送给其中的一个。第一个值会发送给消费者1号,第二个则会发送给消费者2号,第三个又发送给消费者1号.... 关闭生产者时会强制让消费者打印出它们所接收到的值的列表。 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /章节/基础数据类型.md: -------------------------------------------------------------------------------- 1 | # 数字和字符串 2 | 3 | 本节我们将了解最基础的数据类型,数字和字符串。打开你的`Python REPL`并写出以下语句。 4 | ``` 5 | >>> a = 2 6 | >>> type(a) 7 | 8 | >>> b = 2.5 9 | >>> type(b) 10 | 11 | ``` 12 | 这样你就定义了两个变量(“a”和“b”)它们保存了一些数字:变量“a”保存的是一个整数,而“b”保存的是一个实数。 13 | 我们现在可以使用刚才定义的两个变量或者使用其他数字来做些计算: 14 | 15 | ``` 16 | >>> a + b 17 | 4.5 18 | >>> (a + b) * 2 19 | 9.0 20 | >>> 2 + 2 + 4 - 2/3 21 | 7.333333333333333 22 | ``` 23 | Python还支持**字符串**类型。字符串是一些连续的字符(比如一个单词),可以使用单引号或双引号来定义: 24 | ``` 25 | >>> hi = "hello" 26 | >>> hi 27 | 'hello' 28 | >>> bye = 'goodbye' 29 | >>> bye 30 | 'goodbye' 31 | ``` 32 | 你可以将两个字符串相加来连接它们,但你不能将两个不同的数据类型相加,比如一个字符串一个整数。 33 | ``` 34 | >>> hi + "world" 35 | 'helloworld' 36 | >>> "Hello" + 3 37 | Traceback (most recent call last): 38 | File "", line 1, in 39 | TypeError: must be str, not int 40 | ``` 41 | 你可以用乘来将原字符串翻倍: 42 | ``` 43 | >>> "Hello" * 3 44 | 'HelloHelloHello' 45 | ``` 46 | 47 | ## 数字部分练习 48 | 1. 猜一下进行以下数学计算会发生什么: ((3 / 2)), ((3 // 2)), ((3 % 2)), ((3\*\*2)) 49 | 提示: 阅读下 https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex 学习更多关于计算的内容。 50 | 51 | 2. 计算下列数字序列的平均数: (2, 4), (4, 8, 9), (12, 14/6, 15) 52 | 53 | 3. 一个球体的体积是(4/3 * pi * r^3)。 请计算出一个半径为5的球体的体积。 54 | 提示: 可以创建一个值为`3.1415`的变量`pi`。 55 | 56 | 4. 使用取模运算(%)来检查下列数字是单数还是双数:(1, 5, 20, 60/7)。 57 | 58 | 提示: 当(x)是双数时,(x/2)总会是0。 59 | 60 | 5. 请找到合适的(x)和(y)可以让(x < 1/3 < y)在Python REPL中返回**True**。 61 | 提示: (0 < 1/3 < 1)。 62 | 63 | 64 | ## 字符串部分练习 65 | 66 | 参阅Python 中关于字符串的文档(https://docs.python.org/3/library/stdtypes.html?#text-sequence-type-str), 然后来解决下列问题: 67 | 68 | 1. 初始化一个字符串为`"abc"`,并将其赋值给变量`"s"`: 69 | > 1. 使用一个函数获取出该字符串的长度。 70 | > 2. 使用一些操作符让`"abc"`变成`"aaabbbccc"`。 71 | 提示:连接与索引。 72 | 73 | 2. 初始化一个字符串为`"aaabbbccc"`,并将其赋值给变量`"s"`: 74 | > 1. 使用一个函数获取出`"b"`第一次出现的位置,以及`"ccc"`第一次出现的位置。 75 | > 2. 使用一个函数替换所有的`"a"`为`"X"`,然后使用相同的函数只替换第一个`"a"`为`"X"`。 76 | 77 | 3. 给你一个字符串`"aaa bbb ccc"`,使用什么操作可以让它们变成以下字符串? 你可以使用`replace`函数。 78 | > 1. "AAA BBB CCC" 79 | > 2. "AAA bbb CCC" 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /章节/字典.md: -------------------------------------------------------------------------------- 1 | # 字典 2 | 3 | 本节我们的主角是Python中的字典。字典是一个数据结构,通过给定key来获取响应的值(是一个key-value对的形式)。 4 | 下面的例子展示了以同学的名字为索引,值为年龄的字典: 5 | ``` 6 | ages = { 7 | "Peter": 10, 8 | "Isabel": 11, 9 | "Anna": 9, 10 | "Thomas": 10, 11 | "Bob": 10, 12 | "Joseph": 11, 13 | "Maria": 12, 14 | "Gabriel": 10, 15 | } 16 | >>> print(ages["Peter"]) 17 | 10 18 | ``` 19 | 使用字典的`items`可以迭代出其中的内容,比如这样: 20 | ``` 21 | >>> for name, age in ages.items(): 22 | ... print(name, age) 23 | ... 24 | Peter 10 25 | Isabel 11 26 | Anna 9 27 | Thomas 10 28 | Bob 10 29 | Joseph 11 30 | Maria 12 31 | Gabriel 10 32 | ``` 33 | 不过,字典的key并不需要是一个字符串,它可以是任何[不可变](https://docs.python.org/3/tutorial/datastructures.html#dictionaries)对象: 34 | ``` 35 | d = { 36 | 0: [0, 0, 0], 37 | 1: [1, 1, 1], 38 | 2: [2, 2, 2], 39 | } 40 | >>> d[2] 41 | [2, 2, 2 42 | ``` 43 | 同时你可以将另一个字典作为某个值写入: 44 | ``` 45 | students = { 46 | "Peter": {"age": 10, "address": "Lisbon"}, 47 | "Isabel": {"age": 11, "address": "Sesimbra"}, 48 | "Anna": {"age": 9, "address": "Lisbon"}, 49 | } 50 | >>> students['Peter'] 51 | {'age': 10, 'address': 'Lisbon'} 52 | >>> students['Peter']['address'] 53 | 'Lisbon' 54 | ``` 55 | 也正因为这样,这种数据结构非常容易书写阶级式内容。 56 | 57 | ## 字典部分练习 58 | 59 | 自行研究Python文档 https://docs.python.org/3/library/stdtypes.html#mapping-types-dict 来解决下列练习。 60 | 61 | 先定义一个Python字典: 62 | ``` 63 | ages = { 64 | "Peter": 10, 65 | "Isabel": 11, 66 | "Anna": 9, 67 | "Thomas": 10, 68 | "Bob": 10, 69 | "Joseph": 11, 70 | "Maria": 12, 71 | "Gabriel": 10, 72 | } 73 | ``` 74 | 75 | 1. 这个字典中有多少只同学?提示:**len**函数。 76 | 2. 写一个函数,接受“ages”字典作为参数,返回其年龄的平均值。 77 | 遍历字典中所有的项可以使用**items**方法。 78 | 3. 写一个函数,接受“ages”字典作为参数,返回其中年龄最大的同学的名字。 79 | 4. 写一个函数,接受“ages”字典和数字“n”作为参数,返回的是一个新字典,新字典中每个同学的年龄均是“n”。比如,`new_ages(ages, 10)`返回的是“ages”字典的拷贝并且每个同学的年龄都是10。 80 | 81 | ## 子字典部分练习 82 | 83 | 先定义一个字典: 84 | ``` 85 | students = { 86 | "Peter": {"age": 10, "address": "Lisbon"}, 87 | "Isabel": {"age": 11, "address": "Sesimbra"}, 88 | "Anna": {"age": 9, "address": "Lisbon"}, 89 | } 90 | ``` 91 | 1. “students”字典中有多少只同学? 92 | 2. 写一个函数接受“students”字典,返回平均年龄。 93 | 3. 写一个函数接受“students”字典和一个地址(address)参数,返回一个列表,内容是所有与传入的地址相匹配的同学的名字。 94 | 比如,调用`find_students(students, 'Lisbon')`会返回`['Peter', 'Anna']`。 95 | 96 | 97 | -------------------------------------------------------------------------------- /章节/安装.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 本节我们将会安装Python到我们的本地电脑中。 3 | 4 | ## 在Windows上安装 5 | 6 | 1. 首先从 https://www.python.org/downloads/windows/ 上选择合适的Python 3版本下载并执行安装。写作本书时最新的版本是3.6.4。 7 | 8 | 2. 确保勾选了“Install launcher for all users (为所有用户执行安装)”和“Add Python to PATH (将Python添加到环境目录中)”并选择“Customize installation (自定义安装)”。 9 | 10 | ![windows_installation_0](../images/python_windows.jpg) 11 | 12 | 3. 在下一个视图"Optional Features"中选择需要添加的东西,不过请确保“pip”和“Pylauncher (for all users)”是勾选的。 pip是Python的包管理器,可以让你很方便地安装Python包。 13 | 14 | 4. 在接下来的“Advanced Options”中确保勾选了"Add Python to enviroment variables"。同时我建议你修改一下安装目录,比如使用“C:\Python36\”,这样在需要时可以很方便得找到Python的安装目录。 15 | 16 | ![windows_installation_1](../images/python_windows2.jpg) 17 | 18 | 5. 最后,允许Python在文件系统上可以超过260个字符,这一条要选择“Disable path length limit (禁用路径长度限制)”并关闭安装对话框。 19 | 20 | ![windows_installation_2](../images/python_windows3.jpg) 21 | 22 | 6. 现在,打开命令行 (cmd)并输出`python`或`python3`。如果安装的过程顺利,那你应该会看到`Python REPL`。`REPL(意思是读取,评估,打印,循环)`是一个允许你编写一些小型Python编码的环境。最后使用`exit()`关掉`REPL`。 23 | 24 | ![windows_installation_3](../images/python_windows4.jpg) 25 | 26 | ## 在macOS上安装 27 | 你可以从 https://www.python.org/downloads/mac-osx/ 上选择合适的安装包下载。确保你下载的是最新的Python 3(写作时最新版本是3.6.4)。 同时你可以使用 **Homebrew**(https://brew.sh/) 来进行下载。 28 | 使用**Homebrew**只需要在终端输入`brew install python3`即可。你也可以使用**MacPorts**包管理器(https://www.macports.org/) 进行下载,所需要的命令是`port install python36`。 29 | 30 | ![macos_installation_0](../images/python_macos.png) 31 | 32 | 最后,打开终端并输入`python3`你应该会看到`Python REPL`。按下`Ctrl + D`或输入`exit()`可以退出。 33 | 34 | 35 | ## 在Linux上安装 36 | 37 | 在Linux上安装Python,你可以在 https://www.python.org//downloads/source/ 中下载最新的Python 3 源码,或者使用包管理器(apt-get, aptitude, synaptic或者其他的)来安装。 之后确保你已经成功安装了Python 3,你可以运行`python3 --version`来查看是否已经安装成功。 38 | 39 | 最后在终端中输入`python3`你就可以看到Python REPL出现了。 按下`Ctrl + D`或输入`exit()`可以退出。 40 | 41 | ![linux_installation_0](../images/python_linux.png) -------------------------------------------------------------------------------- /章节/异步.md: -------------------------------------------------------------------------------- 1 | # 异步编程 2 | 3 | 目前为止,我们在做的都是*同步编程*。同步编程执行过程很简单:一个程序从第一行开始,逐行执行一直到末尾。每次调用一个函数时,程序就会等待这个函数返回然后在执行下一行。 4 | 5 | 在异步编程中,函数地执行通常是**非阻塞**的。换句话说,每次你调用一个函数它就会立即返回,但相对得,这就表示函数并不会立即被执行。它有了一种机制(名为 调度程序),可以让它随时在未来执行这些函数。 6 | 7 | 使用异步编程会导致程序在任何异步函数开始之前就有可能结束掉。通常的解决方法是让异步函数返回“future(未来任务)”或者“promises(预先任务)”。让其标识出这是一个异步函数。最终,由有调度程序的异步编程框架阻塞或者说等待这些异步函数完成它们的“future(未来任务)”。 8 | 9 | 自Python 3.6开始,“asyncio”模块与*async*和*await*关键字相结合,来让我们写*多任务协作程序*。在此类编程中,当一个协同函数在开小差或者等待输入时,都会由*yield*交出控制权给另一个协同函数。 10 | 11 | 12 | 思考一下下面这个异步函数,它的作用是返回一个数字的平方,并且在返回前会睡眠一秒钟。 13 | 异步函数由`async def`声明。现在先忽略其中的`await`关键字: 14 | ``` 15 | import asyncio 16 | 17 | async def square(x): 18 | print('Square', x) 19 | await asyncio.sleep(1) 20 | print('End square', x) 21 | return x * x 22 | 23 | # 创建一个事件循环。 24 | loop = asyncio.get_event_loop() 25 | 26 | # 执行异步函数并且等待其完成。 27 | results = loop.run_until_complete(square(1)) 28 | print(results) 29 | 30 | # 将事件循环关闭。 31 | loop.close() 32 | ``` 33 | 事件循环(https://docs.python.org/3/library/asyncio-eventloop.html )是在有很多事物时,Python可以使用调度机制来执行这些异步函数的一种方式。我们使用循环来让这些函数运行直到完成。这是一种同步机制,目的是让我们得到任何结果前(`await asyncio.sleep(1)`),剩下的打印语句都不会被执行。 34 | 。 35 | 36 | 之前的例子并不能很好地说明异步编程,因为我们没有写得很复杂,而且也只执行了一次函数。不过你可以想一下,如果你要执行`square(x)`3次呢: 37 | ``` 38 | square(1) 39 | square(2) 40 | square(3) 41 | ``` 42 | 因为`square()`里面有一个睡眠函数,总执行时间差不多要3秒钟。但每次执行一个函数时计算机就会陷入呆滞,在那一秒钟里什么也不做,我们为什么不能让它在之前的那个函数睡眠时来执行下一个呢?我们稍加改动,把它变成异步: 43 | ``` 44 | # 执行异步函数直到其完成。 45 | results = loop.run_until_complete(asyncio.gather( 46 | square(1), 47 | square(2), 48 | square(3) 49 | )) 50 | print(results) 51 | ``` 52 | 53 | 一般来说,我们使用`asyncio.gather(*tasks)`来让循环等待所有的任务完成。因为协同程序几乎会在同一时间内启动,整个程序只需要1秒钟即可完成。要注意,**asyncio.gather()**不会按顺序执行协同函数,尽管它会返回一个按顺序排列的结果列表。 54 | ``` 55 | $ python3 python_async.py 56 | Square 2 57 | Square 1 58 | Square 3 59 | End square 2 60 | End square 1 61 | End square 3 62 | [1, 4, 9] 63 | ``` 64 | 65 | 有时我们需要立即处理所返回的结果。对于这种情况,我们可以使用两个协同函数,让第二个来处理结果,使用`asyncio.as_completed()`就可以: 66 | ``` 67 | (...) 68 | 69 | async def when_done(tasks): 70 | for res in asyncio.as_completed(tasks): 71 | print('Result:', await res) 72 | 73 | loop = asyncio.get_event_loop() 74 | loop.run_until_complete(when_done([ 75 | square(1), 76 | square(2), 77 | square(3) 78 | ])) 79 | ``` 80 | 打印出的东西差不多是这样的: 81 | ``` 82 | Square 2 83 | Square 3 84 | Square 1 85 | End square 3 86 | Result: 9 87 | End square 1 88 | Result: 1 89 | End square 2 90 | Result: 4 91 | ``` 92 | 最后要说的是,异步函数中可以使用`await`关键字来调用另一个异步函数。 93 | ``` 94 | async def compute_square(x): 95 | await asyncio.sleep(1) 96 | return x * x 97 | 98 | async def square(x): 99 | print('Square', x) 100 | res = await compute_square(x) 101 | print('End square', x) 102 | return res 103 | ``` 104 | 105 | # 异步编程部分练习 106 | 107 | 1. 写一个异步协同函数,它接受两个参数,并将它们相加,并且之后会睡眠这些秒。请使用异步循环来调用它。 108 | 2. 修改一下之前的那个程序,让它调用两次。 109 | 110 | 111 | -------------------------------------------------------------------------------- /章节/模块和函数.md: -------------------------------------------------------------------------------- 1 | # 模块和函数 2 | 3 | 本节我们要讨论下模块和函数。 4 | 一个函数是一块用来执行单个操作的代码块。 5 | 一个模块则是一个Python文件,里面包含了变量,函数和其他东西。 6 | 7 | 我们启动Python REPL然后导入**math**模块,这个模块提供了一些数学方面的函数: 8 | ``` 9 | >>> import math 10 | >>> math.cos(0.0) 11 | 1.0 12 | >>> math.radians(275) 13 | 4.799655442984406 14 | ``` 15 | 函数是包含了一组表达内容的序列,在调用的时候会被执行出来。 16 | 下面我们定义了一个`do_hello`函数,它的作用是打印两条信息: 17 | ``` 18 | >>> def do_hello(): 19 | ... print("Hello") 20 | ... print("World") 21 | ... 22 | >>> do_hello() 23 | Hello 24 | World 25 | ``` 26 | 确保你在函数中的**print**表达式前插入了一个**tab**。 27 | 在Python中**tab**和**space**非常重要,定义一个代码块或多或少都会依赖于这样的结构。 28 | 比如,**print**表达式被包含在`do_hello`函数里面时,就必须有一个**tab**。 29 | 30 | 函数还可以接受参数,并且也能返回一个值(使用**return**关键字来完成)。 31 | ``` 32 | >>> def add_one(val): 33 | ... print("Function got value", val) 34 | ... return val + 1 35 | ... 36 | >>> value = add_one(1) 37 | Function got value 1 38 | >>> value 39 | 2 40 | ``` 41 | 42 | ## 函数部分练习 43 | 44 | 1. 定义一个名为**add2**的函数,它接受两个数字作为参数,返回的值为这两个数字之和。之后定义一个名为**add3**的函数,它接受3个数字并且返回这三个数字的和。 45 | 46 | 2. 定义一个函数,返回接受的两个数字中较大的那个数字。你可以使用**if**关键字来比较两个数字: https://docs.python.org/3/tutorial/controlflow.html#if-statements 。 47 | 48 | 3. 定义一个名为**is_divisible**的函数,它接受两个参数(“a”和“b”),如果“a”可以被“b”整除那么返回`True`否则返回`False`。 49 | 提示: 一个数字可以被另一个数字整除时,它余下的部分为0。你可以使用取模操作符(%)来计算。 50 | 51 | 4. 定义一个名为**average**的函数,计算出所传入的列表的平均值。你可以使用`sum`和`len`函数。 52 | 53 | 54 | ## 递归函数 55 | 56 | 在计算机编程中,递归函数的意思是调用自身。比如一个阶乘函数 57 | ``` 58 | f(x) = 59 | { 1, if x = 0. } 60 | { x × f(x − 1), otherwise. } 61 | ``` 62 | 作为例子,我们传入5,它的计算过程是这样的: 63 | ``` 64 | 5! = 5 × 4! 65 | = 5 × 4 × 3! 66 | = 5 × 4 × 3 × 2! 67 | = 5 × 4 × 3 × 2 × 1 68 | ``` 69 | 70 | 5的阶乘本质上是5乘4的阶乘...最终,是1(或0)的阶乘也就是1然后结束递归。在Python中,我们可以这样写: 71 | ``` 72 | def factorial(x): 73 | if x == 0: 74 | return 1 75 | else: 76 | return x * factorial(x-1) 77 | ``` 78 | 79 | 递归的要点必须有一个**基础**条件,在这个条件下递归会终止,而递归的过程必须逐渐靠近这个**基础**条件。 80 | 阶乘这个例子中,我们知道数字为0时阶乘的结果是1,然后当阶乘的数大于0时则是之前数字的阶乘一直延续到0。 81 | 82 | ## 递归函数的练习 83 | 84 | 1. 写一个阶乘函数并测试几个不同的数据。同时使用计算器来验证其正确性。 85 | 2. 写一个递归函数,该函数会计算出1到(n)之间整数的和(n作为参数传入)。想想**基础**条件应该是什么(是不是加到0为止?),思考下递归例子是怎么做的。 86 | 3. 斐波那契数列是一个数字序列,它的每一个数字都是前2个数字之和。请根据以下信息,写出一个递归函数来计算斐波那契数列(fib(n))。 87 | ``` 88 | fib(n) = 89 | { 0, if x = 0. } 90 | { 1, if x = 1. } 91 | { fib(n − 1) + fib(n − 2), otherwise } 92 | ``` 93 | 检查下你最初的几个结果是否与结果对应了:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... 94 | 95 | 96 | -------------------------------------------------------------------------------- /章节/生成器.md: -------------------------------------------------------------------------------- 1 | # 生成器 2 | 3 | 如果读过前一节,那你应该已经知道“迭代器”指的是一种可以被“for”循环使用的对象。换句话说,迭代器就是遵循迭代协议的对象。 4 | 而生成器则是迭代器的一种更为简洁的实现方法。这种写法不再需要构造一个类,而只需编写一个函数,函数每次运行到“yield”语句时都会返回一个值。下面的例子是用生成器来依次生成两个数之间的整数: 5 | ``` 6 | def myrange(a, b): 7 | while a < b: 8 | yield a 9 | a += 1 10 | ``` 11 | 与其他迭代器一样,生成器也可以用在“for”循环里: 12 | ``` 13 | >>> for value in myrange(1, 4): 14 | ... print(value) 15 | ... 16 | 1 17 | 2 18 | 3 19 | ``` 20 | 生成器与迭代器大同小异: 21 | ``` 22 | >>> seq = myrange(1,3) 23 | >>> next(seq) 24 | 1 25 | >>> next(seq) 26 | 2 27 | >>> next(seq) 28 | Traceback (most recent call last): 29 | File "", line 1, in 30 | StopIteration 31 | ``` 32 | 相比普通函数而言,生成器的要点在于“yield”这个关键字。“yield”关键字很像“return”关键字,但不同于“return”的是,它允许函数在返回一个值后重新恢复执行。换句话说,每当函数调用方想从生成器中取出下一个值的时候,Python 就会从“yield”关键字处唤醒这个已暂停的函数并继续往下执行,直到函数完全退出为止。 33 | 34 | 生成器函数当中同样可以调用其他生成器。比如,我们常用“range”函数来生成一组数字序列: 35 | ``` 36 | def squares(n): 37 | for value in range(n): 38 | yield value * value 39 | ``` 40 | 41 | ## 生成器部分练习 42 | 43 | 1. 写一个名为“squares”的生成器来生成(a)到(b)之间所有整数的平方,并用“for”循环来测试它。 44 | 2. 用生成器来生成所有1到(n)之间的双数。 45 | 3. 用生成器来生成所有1到(n)之间的单数。 46 | 4. 编写一个生成器,按降序输出(n)到 0 之间的整数。 47 | 5. 编写一个生成器,生成斐波那契数列当中小于(n)的数字。斐波那契数列的前几个数字是: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... 48 | 6. 编写一个生成器,生成 0 到(n)之间所有的相邻数对,形如 (0, 1), (1, 2), (2, 3)... 49 | -------------------------------------------------------------------------------- /章节/简介.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 本书的目的是以实际例子来教会大家Python这门编程语言。方法很简单:每一个主题都有一个简短的介绍,读者通过解决实际的问题来学的更多知识。 4 | 5 | 这些实例被广泛用在我在Superior科技学院的web开发与分布式计算课程中。通过这些实例,学生们可以在一个月内快速掌握Python。实际上,曾在第二学年学习过软件工程的学生,可以在二周内熟悉Python的语法,并在第三周使用sockets写出分布式计算网络的客户端。 6 | 7 | 请注意,本书仍在不断创作,可能会包含一些拼写错误。但对于想使用它来进行学习的人来说,这应该不会成为一个很大的困难。同时,真心祝愿你能从本书中获益。 8 | 9 | 本书中的源码发布在github上。同时欢迎各位发起PR来纠正拼写错误,发布新的练习项目,对目前已存在的项目提供更详细的说明等。 10 | 11 | 学习的路上一路顺风~。 12 | 13 | -------------------------------------------------------------------------------- /章节/类.md: -------------------------------------------------------------------------------- 1 | # 类 2 | 3 | 在面向对象编程(OOP)中,类是一个允许一组属性和函数(一般称方法)糅合在一起的数据结构。 4 | 下面定义的这个**Person**类定义了“name”和“age”属性,同时还有一个“greet”方法: 5 | ``` 6 | class Person: 7 | def __init__(self, name, age): 8 | self.name = name 9 | self.age = age 10 | 11 | def greet(self): 12 | print("Hello, my name is %s!" % self.name) 13 | ``` 14 | 大部分类都需要构造方法(`__init__`)来初始化类的一些属性。在之前的代码中,这个类的构造方法接收一个人的名字和年龄并将这些信息保存在类的实例中(使用`self`关键字访问的)。 15 | “greet”方法则是打印存储在类实例(object)中的名字(name)。 16 | 类实例通过实例化到对象中使用。下面的代码展示了我们如何实例化两个对象: 17 | ``` 18 | >>> a = Person("Peter", 20) 19 | >>> b = Person("Anna", 19) 20 | >>> a.greet() 21 | Hello, my name is Peter! 22 | >>> b.greet() 23 | Hello, my name is Anna! 24 | >>> print(a.age) # We can also access the attributes of an object 25 | 20 26 | ``` 27 | 28 | ## 类部分练习 29 | 30 | 自行研究Python文档: https://docs.python.org/3/tutorial/classes.html 完成下列练习: 31 | 1. 写一个名为“Rectangle” 的类,存储给定的长方形坐标(x1, y1), (x2, y2)。 32 | 2. “Rectangle”类的构造方法接受4个参数(x1, y1, x2, y2)使用**self**关键字将它们存到类实例中。 33 | 3. 给这个类写一个`width()`方法和`height()`方法,分别返回这个长方形的宽和高。创建两个“Rectangle”实例对象来测试一下。 34 | 4. 再写一个`area`方法,作用是返回这个长方形的面积(宽\*高)。 35 | 5. 最后写一个`circumference`方法,返回的是这个长方形的周长(宽\*高\*2)。 36 | 6. 将`__str__`方法改写为返回长方形坐标`(x1, y1)(x2, y2)`。然后打印所创建的类对象中的一个进行测试。 37 | 38 | ## 类继承 39 | 40 | 在面向对象编程中,继承是一种子类可以从另一个类中得到其属性和方法的形式,并允许其重写超类(被继承的类)的功能。 41 | 比如,基于我们上面写的“Person”类,我们创建一个子类,让这个子类的所产生的人年龄总为10: 42 | ``` 43 | class TenYearOldPerson(Person): 44 | def __init__(self, name): 45 | super().__init__(name, 10) 46 | 47 | def greet(self): 48 | print("I don't talk to strangers!!") 49 | ``` 50 | 在第一行中指出“TenYearOldPerson”类是“Person”类的子类。之后我们重写子类的构造方法,让它只接受人的名字,但最终我们还要调用超类(被继承的类)的构造方法,参数是这个人的名字和年龄10。最后我们重写了“greet”方法。 51 | 52 | ## 继承部分练习 53 | 54 | 使用之前定义的“Rectangle”类来进行下列练习: 55 | 1. 创建一个“Square”类,它是“Rectangle”的子类。 56 | 2. 为“Square”类写上构造方法。构造方法只包含x1, y1两个坐标以及正方形的大小。记住,当你使用“super”来调用“Rectangle”的构造方法时你仍会用到这些参数。 57 | 3. 实例化两个“Square”对象,调用`area`方法并打印这个对象。确保所有的计算返回的是正确的结果,传入参数时应保证正方形的坐标始终与正方形的大小一致。 58 | 59 | -------------------------------------------------------------------------------- /章节/迭代与循环.md: -------------------------------------------------------------------------------- 1 | # 迭代与循环 2 | 3 | 本节我们探索的主题是*迭代*与*循环*。循环通常在计算机编程用用于自动执行重复性任务。 4 | 在Python中最常用的迭代形式就是**for**循环了。**for**循环允许你迭代出列表中所有的项,迭代出来后你可以做任何你想做的事情。 5 | 比如,我们创建了一个列表,并打印出其中所有元素的平方。 6 | ``` 7 | >>> for value in [0, 1, 2, 3, 4, 5]: 8 | ... print(value * value) 9 | ... 10 | 0 11 | 1 12 | 4 13 | 9 14 | 16 15 | 25 16 | ``` 17 | 这样的形式简单又好用!**for**循环是许多编程中的基础。 18 | 比如,你已经知道的**sum(list)**这个函数,它会将列表中所有的元素相加,但你同样可以使用**for**循环来干这件事情: 19 | ``` 20 | >>> mylist = [1,5,7] 21 | >>> sum = 0 22 | >>> for value in mylist: 23 | ... sum = sum + value 24 | ... 25 | >>> print(sum) 26 | 13 27 | ``` 28 | 其本质是创建了一个变量"sum",然后不断的将列表中的元素与其相加。 29 | 30 | 有时候,你可能会想使用列表中索引,比如不迭代出其中的值,迭代出它所在列表的索引位置。 31 | 请看以下例子: 32 | ``` 33 | >>> mylist = [1,5,7] 34 | >>> for i in range(len(mylist)): 35 | ... print("Index:", i, "Value:", mylist[i]) 36 | ... 37 | Index: 0 Value: 1 38 | Index: 1 Value: 5 39 | Index: 2 Value: 7 40 | ``` 41 | 42 | 可以看到我们并没有迭代列表本身,而是迭代了这个列表长度的“range”。“range”函数返回的是一个*特殊*列表: 43 | ``` 44 | >>> list(range(3)) 45 | [0, 1, 2] 46 | ``` 47 | 所以当使用“range”时迭代的就不是“mylist”而是一些用于访问列表里的值的数字索引。更多关于“range”的内容你可以参阅Python文档中关于“range”的部分。 https://docs.python.org/3/tutorial/controlflow.html#the-range-function 48 | 49 | 有时你可能同时需要这两个(索引和值),这时你可以使用**enumerate**函数: 50 | ``` 51 | >>> mylist = [1,5,7] 52 | >>> for i, value in enumerate(mylist): 53 | ... print("Index:", i, "Value:", value) 54 | ... 55 | Index: 0 Value: 1 56 | Index: 1 Value: 5 57 | Index: 2 Value: 7 58 | ``` 59 | 请记住Python列表中第一个值的索引总是0。 60 | 61 | 最后,Python里还提供**while**语句来让我们重复做一些事情,只要这个特定的条件是**True**就会一直执行。 62 | 比如,下面这个例子中*n*开始于10,条件是**“n”大于0**。每次都会从*n*中减去1。当*n*变为0时,**“n”>0**这个条件就失效了,此循环也就结束了。 63 | ``` 64 | >>> n = 10 65 | >>> while n > 0: 66 | ... print(n) 67 | ... n = n-1 68 | ... 69 | 10 70 | 9 71 | 8 72 | 7 73 | 6 74 | 5 75 | 4 76 | 3 77 | 2 78 | 1 79 | ``` 80 | 这个循环永远也不会打印0。 81 | 82 | ## for循环部分练习 83 | 解决这一部分你可能要参阅Python文档中关于循环的部分: https://docs.python.org/3/tutorial/controlflow.html#for-statements 84 | 85 | 1. 创建一个函数**add**,它接受一个列表作为参数,返回的是列表中所有元素的和。请使用**for**循环来完成。 86 | 87 | 2. 创建一个函数,它接受一个列表作为参数,返回的是列表中最大的一个数。 88 | 提示:每迭代完一次你可能都要保存一下目前为止得到的最大的数以进行比较。 89 | 90 | 3. 修改之前的那个函数,现在它返回的是一个列表,列表中第一个元素为最大的一个值,第二个元素为这个值在原列表中的位置。 91 | 提示:除了保存目前为止最大的数,你还要保存下它出现的位置。 92 | 93 | 4. 实现一个函数,它返回所接受的列表的翻转列表。 94 | 提示:你可以创建一个空列表,然后从原列表中倒序的添加值。你可能要参阅Python文档中关于列表的部分来完成: 95 | https://docs.python.org/3/tutorial/datastructures.html#more-on-lists 96 | 97 | 5. 写一个**is_sorted**函数,它接受一个列表作为参数,如果这个列表里的内容是以升序排列的话则返回**True**。 98 | 比如`[1, 2, 2, 3]`就是**True**,`[1, 2, 3, 2]`则不是。 99 | 提示:如果你要将一个数字与接下来的数字做对比,你可能会用到索引,或者你也可以将其保存到一个变量中。 100 | 101 | 6. 写一个**is_sorted_dec**函数,与之前的那个相似但所有的项都是以降序排列的。 102 | 103 | 7. 写一个**has_duplicates**函数,验证所传入的列表里是否存在重复的数。 104 | 提示:你可能需要使用两个**for**循环,在一个**for**循环里在使用一个**for**来检查是否有重复的数。 105 | 106 | ## while循环部分练习 107 | 108 | 1. 写一个函数,接受一个数字作为参数并且以降序形式打印出来,打印时标出该数字是奇数还是偶数,一直持续到0为止。 109 | ``` 110 | >>> even_odd(10) 111 | Even number: 10 112 | Odd number: 9 113 | Even number: 8 114 | Odd number: 7 115 | Even number: 6 116 | Odd number: 5 117 | Even number: 4 118 | Odd number: 3 119 | Even number: 2 120 | Odd number: 1 121 | ``` 122 | 123 | 124 | -------------------------------------------------------------------------------- /章节/迭代器.md: -------------------------------------------------------------------------------- 1 | # 迭代器 2 | 3 | 正如我们之前学到的,在Python中我们可以使用“for”循环来迭代出对象中的内容: 4 | ``` 5 | >>> for value in [0, 1, 2, 3, 4, 5]: 6 | ... print(value) 7 | ... 8 | 0 9 | 1 10 | 4 11 | 9 12 | 16 13 | 25 14 | ``` 15 | 16 | 可以使用“for”循环(迭代)的对象称为迭代器。因此,一个迭代器也就是一个遵循了迭代协议的对象。 17 | 18 | 内置函数“iter”可以用来创建一个迭代对象,这时使用“next”函数可以来逐步迭代出内容: 19 | ``` 20 | >>> my_iter = iter([1, 2, 3]) 21 | >>> my_iter 22 | 23 | >>> next(my_iter) 24 | 1 25 | >>> next(my_iter) 26 | 2 27 | >>> next(my_iter) 28 | 3 29 | >>> next(my_iter) 30 | Traceback (most recent call last): 31 | File "", line 1, in 32 | StopIteration 33 | ``` 34 | 当没有更多元素时,迭代器就会抛出“StopIteration”异常。 35 | 36 | ## 迭代器类 37 | 38 | 迭代器可以部署在类中。你只需要重写“__next__”和“__iter__”方法即可。 39 | 我们写一个模仿“range”函数的类作为例子,作用是返回所有“a”和“b”之间的值: 40 | ``` 41 | class MyRange: 42 | def __init__(self, a, b): 43 | self.a = a 44 | self.b = b 45 | 46 | def __iter__(self): 47 | return self 48 | 49 | def __next__(self): 50 | if self.a < self.b: 51 | value = self.a 52 | self.a += 1 53 | return value 54 | else: 55 | raise StopIteration 56 | ``` 57 | 这样我们每次调用“next”时它都会让存储在内部的a前进,并且返回它的值。当它到达b时,就抛出“StopIteration”异常。 58 | ``` 59 | >>> myrange = MyRange(1, 4) 60 | >>> next(myrange) 61 | 1 62 | >>> next(myrange) 63 | 2 64 | >>> next(myrange) 65 | 3 66 | >>> next(myrange) 67 | Traceback (most recent call last): 68 | File "", line 1, in 69 | StopIteration 70 | ``` 71 | 最重要的是,你可以将迭代器类用在**for**循环中: 72 | ``` 73 | >>> for value in MyRange(1, 4): 74 | ... print(value) 75 | ... 76 | 1 77 | 2 78 | 3 79 | ``` 80 | 81 | ## 迭代器部分练习 82 | 83 | 1. 写一个迭代器类,返回的是所有“a”到“b”之间的整数的平方。 84 | 2. 写一个迭代器类,返回所有1到(n)之间的偶数。 85 | 3. 写一个迭代器类,返回所有1到(n)之间的奇数。 86 | 4. 写一个迭代器类,返回所有(n)到0之间的整数。 87 | 5. 写一个迭代器类,返回的是从第一个元素到(n)之间所有的斐波那契数列。你可以回顾下**函数**部分了解下什么是斐波那契数列。 88 | 这是斐波那契数列的前几个数:`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...`。 89 | 6. 写一个迭代器类,返回的是所有0到(n)的连续对,如(0, 1), (1, 2), (2, 3)...。 90 | 91 | --------------------------------------------------------------------------------