Merge pull request #2 from jackfrued/master

更新
pull/321/head
usegitforpython 2020-05-04 13:14:13 +08:00 committed by GitHub
commit 7eeee82883
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
373 changed files with 7679 additions and 2829 deletions

View File

@ -5,36 +5,36 @@
#### Python的历史
1. 1989年圣诞节Guido von Rossum开始写Python语言的编译器。
2. 1991年2月第一个Python编译器同时也是解释器诞生它是用C语言实现的后面又出现了Java和C#实现的版本Jython和IronPython除此之外还有PyPy、Brython、Pyston等其他实现可以调用C语言的库函数。在最早的版本中Python已经提供了对“类”“函数”“异常处理”等构造块的支持还有对列表、字典等核心数据类型同时支持以模块为基础来构造应用程序。
2. 1991年2月第一个Python编译器同时也是解释器诞生它是用C语言实现的后面可以调用C语言的库函数。在最早的版本中Python已经提供了对“类”“函数”“异常处理”等构造块的支持还有对列表、字典等核心数据类型同时支持以模块为基础来构造应用程序。
3. 1994年1月Python 1.0正式发布。
4. 2000年10月16日Python 2.0发布,增加了完整的[垃圾回收](https://zh.wikipedia.org/wiki/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8)),提供了对[Unicode](https://zh.wikipedia.org/wiki/Unicode)的支持。与此同时Python的整个开发过程更加透明社区对开发进度的影响逐渐扩大生态圈开始慢慢形成。
5. 2008年12月3日Python 3.0发布它并不完全兼容之前的Python代码不过因为目前还有不少公司在项目和运维中使用Python 2.x版本所以Python 3.x的很多新特性后来也被移植到Python 2.6/2.7版本中。
目前我们使用的Python 3.7.x的版本是在2018年发布的Python的版本号分为三段形如A.B.C。其中A表示大版本号一般当整体重写或出现不向后兼容的改变时增加AB表示功能更新出现新功能时增加BC表示小的改动例如修复了某个Bug只要有修改就增加C。如果对Python的历史感兴趣可以阅读名为[《Python简史》](http://www.cnblogs.com/vamei/archive/2013/02/06/2892628.html)的博文
目前我们使用的Python 3.7.x的版本是在2018年发布的Python的版本号分为三段形如A.B.C。其中A表示大版本号一般当整体重写或出现不向后兼容的改变时增加AB表示功能更新出现新功能时增加BC表示小的改动例如修复了某个Bug只要有修改就增加C。如果对Python的历史感兴趣可以阅读名为[《Python简史》](http://www.cnblogs.com/vamei/archive/2013/02/06/2892628.html)的网络文章
#### Python的优缺点
Python的优点很多简单的可以总结为以下几点。
1. 简单和明确,做一件事只有一种方法。
2. 学习曲线低跟其他很多语言相比Python更容易上手。
3. 开放源代码,拥有强大的社区和生态圈。
4. 解释型语言,天生具有平台可移植性。
5. 对两种主流的编程范式(面向对象编程和函数式编程)都提供了支持。
6. 可扩展性和可嵌入性例如在Python中可以调用C/C++代码。
7. 代码规范程度高,可读性强,适合有代码洁癖和强迫症的人群。
1. 简单明了,学习曲线低,比很多编程语言都容易上手。
2. 开放源代码,拥有强大的社区和生态圈,尤其是在数据分析和机器学习领域。
3. 解释型语言,天生具有平台可移植性,代码可以工作于不同的操作系统。
4. 对两种主流的编程范式(面向对象编程和函数式编程)都提供了支持。
5. 代码规范程度高,可读性强,适合有代码洁癖和强迫症的人群。
Python的缺点主要集中在以下几点。
1. 执行效率稍低,因此计算密集型任务可以由C/C++编写。
1. 执行效率稍低,对执行效率要求高的部分可以由其他语言C、C++编写。
2. 代码无法加密,但是现在很多公司都不销售卖软件而是销售服务,这个问题会被弱化。
3. 在开发时可以选择的框架太多如Web框架就有100多个有选择的地方就有错误。
#### Python的应用领域
目前Python在Web应用开发、云基础设施、DevOps、网络数据采集爬虫、数据分析挖掘、机器学习等领域都有着广泛的应用因此也产生了Web后端开发、数据接口开发、自动化运维、自动化测试、科学计算和可视化、数据分析、量化交易、机器人开发、自然语言处理、图像识别等一系列相关的职位
目前Python在Web应用后端开发、云基础设施建设、DevOps、网络数据采集爬虫自动化测试、数据分析、机器学习等领域都有着广泛的应用。
### 搭建编程环境
### 安装Python解释器
想要开始Python编程之旅首先得在自己使用的计算机上安装Python解释器环境下面将以安装官方的Python解释器为例讲解如何在不同的操作系统上安装Python环境。官方的Python解释器是用C语言实现的也是使用最为广泛的Python解释器通常称之为CPython。除此之外Python解释器还有Java语言实现的Jython、C#语言实现的IronPython以及PyPy、Brython、Pyston等版本有兴趣的读者可以自行了解。
#### Windows环境
@ -55,15 +55,15 @@ yum -y install wget gcc zlib-devel bzip2-devel openssl-devel ncurses-devel sqlit
2. 下载Python源代码并解压缩到指定目录。
```Shell
wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz
xz -d Python-3.7.3.tar.xz
tar -xvf Python-3.7.3.tar
wget https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tar.xz
xz -d Python-3.7.6.tar.xz
tar -xvf Python-3.7.6.tar
```
3. 切换至Python源代码目录并执行下面的命令进行配置和安装。
```Shell
cd Python-3.7.3
cd Python-3.7.6
./configure --prefix=/usr/local/python37 --enable-optimizations
make && make install
```
@ -93,7 +93,7 @@ source .bash_profile
macOS也自带了Python 2.x版本可以通过[Python的官方网站](https://www.python.org)提供的安装文件pkg文件安装Python 3.x的版本。默认安装完成后可以通过在终端执行`python`命令来启动2.x版本的Python解释器启动3.x版本的Python解释器需要执行`python3`命令。
### 从终端运行Python程序
### 运行Python程序
#### 确认Python的版本
@ -102,13 +102,13 @@ macOS也自带了Python 2.x版本可以通过[Python的官方网站](https://
```Shell
python --version
```
或者是在Linux或macOS系统的终端中键入下面的命令。
在Linux或macOS系统的终端中键入下面的命令。
```Shell
python3 --version
```
当然也可以先输入python或python3进入交互式环境再执行以下的代码检查Python的版本。
当然也可以先输入`python``python3`进入交互式环境再执行以下的代码检查Python的版本。
```Python
import sys
@ -139,7 +139,7 @@ python hello.py
python3 hello.py
```
### 代码中的注释
#### 代码中的注释
注释是编程语言的一个重要组成部分,用于在源代码中解释代码的作用从而增强程序的可读性和可维护性,当然也可以将源代码中不需要参与运行的代码段通过注释来去掉,这一点在调试程序的时候经常用到。注释在随源代码进入预处理器或编译时会被移除,不会在目标代码中保留也不会影响程序的执行结果。
@ -154,15 +154,11 @@ python3 hello.py
Version: 0.1
Author: 骆昊
"""
print('hello, world!')
# print("你好,世界!")
print('你好', '世界')
print('hello', 'world', sep=', ', end='!')
print('goodbye, world', end='!\n')
# print("你好, 世界!")
```
### 其他工具介绍
### Python开发工具
#### IDLE - 自带的集成开发工具
@ -172,7 +168,7 @@ IDLE是安装Python环境时自带的集成开发工具如下图所示。但
#### IPython - 更好的交互式编程工具
IPython是一种基于Python的交互式解释器。相较于原生的Python交互式环境IPython提供了更为强大的编辑和交互功能。可以通过Python的包管理工具pip安装IPython和Jupyter,具体的操作如下所示。
IPython是一种基于Python的交互式解释器。相较于原生的Python交互式环境IPython提供了更为强大的编辑和交互功能。可以通过Python的包管理工具pip安装IPython具体的操作如下所示。
```Shell
pip install ipython
@ -188,11 +184,11 @@ pip3 install ipython
![](./res/python-ipython.png)
#### Sublime - 高级文本编辑器
#### Sublime Text - 高级文本编辑器
![](./res/python-sublime.png)
- 首先可以通过[官方网站](https://www.sublimetext.com/)下载安装程序安装Sublime 3或Sublime 2。
- 首先可以通过[官方网站](https://www.sublimetext.com/)下载安装程序安装Sublime Text 3或Sublime Text 2。
- 安装包管理工具。
1. 通过快捷键Ctrl+`或者在View菜单中选择Show Console打开控制台输入下面的代码。
@ -207,9 +203,7 @@ pip3 install ipython
```Python
import urllib2,os;pf='Package Control.sublime-package';ipp=sublime.installed_packages_path();os.makedirs(ipp)ifnotos.path.exists(ipp)elseNone;urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler()));open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read());print('Please restart Sublime Text to finish installation')
```
2. 手动安装浏览器输入 https://sublime.wbond.net/Package%20Control.sublime-package 下载这个文件
下载好以后打开sublime text选择菜单Preferences->Browse Packages... 打开安装目录
此时会进入到一个叫做Packages的目录下点击进入上一层目录Sublime Text3在此目录下有一个文件夹叫做Installed Packages把刚才下载的文件放到这里就可以了。然后重启sublime text3观察Preferences菜单最下边是否有Package Settings 和Package Control两个选项如果有则代表安装成功了。
2. 在浏览器中输入 https://sublime.wbond.net/Package%20Control.sublime-package 下载包管理工具的安装包并找到安装Sublime目录下名为"Installed Packages"的目录把刚才下载的文件放到这个文件加下然后重启Sublime Text就搞定了。
- 安装插件。通过Preference菜单的Package Control或快捷键Ctrl+Shift+P打开命令面板在面板中输入Install Package就可以找到安装插件的工具然后再查找需要的插件。我们推荐大家安装以下几个插件
@ -220,7 +214,7 @@ pip3 install ipython
- Python PEP8 Autoformat - PEP8规范自动格式化插件。
- ConvertToUTF8 - 将本地编码转换为UTF-8。
> 说明:事实上[Visual Studio Code]()可能是更好的选择,它不用花钱并提供了更为完整和强大的功能,有兴趣的读者可以自行研究。
> **说明**:事实上[Visual Studio Code](<https://code.visualstudio.com/>)可能是更好的选择,它不用花钱并提供了更为完整和强大的功能,有兴趣的读者可以自行研究。
#### PyCharm - Python开发神器
@ -230,18 +224,17 @@ PyCharm的安装、配置和使用在[《玩转PyCharm》](../玩转PyCharm.md)
### 练习
1. 在Python交互环境中查看下面的代码结果,并试着将这些内容翻译成中文。
1. 在Python交互式环境中输入下面的代码并查看结果,请尝试将看到的内容翻译成中文。
```Python
import this
```
> 说明当前键入上面的命令后会在交互式环境中看到如下所示的输出这段内容被称为“Python之禅”里面讲述的道理不仅仅适用于Python也适用于其他编程语言。
>
> **说明**输入上面的代码在Python的交互式环境中可以看到Tim Peter撰写的[“Python之禅”](../Python之禅.md)里面讲述的道理不仅仅适用于Python也适用于其他编程语言。
2. 学习使用turtle在屏幕上绘制图形。
> 说明turtle是Python内置的一个非常有趣的模块特别适用于让小朋友体会什么是编程它最早是Logo语言的一部分Logo语言是Wally Feurzig和Seymour Papert在1966发明的编程语言.
> **说明**turtle是Python内置的一个非常有趣的模块特别适合对计算机程序设计进行初体验的小伙伴它最早是Logo语言的一部分Logo语言是Wally Feurzig和Seymour Papert在1966发明的编程语言
```Python
import turtle
@ -259,3 +252,5 @@ PyCharm的安装、配置和使用在[《玩转PyCharm》](../玩转PyCharm.md)
turtle.mainloop()
```
> **提示**:本章提供的代码中还有画国旗和画小猪佩奇的代码,有兴趣的读者请自行研究。

View File

@ -4,17 +4,17 @@
计算机的硬件系统通常由五大部件构成,包括:运算器、控制器、存储器、输入设备和输出设备。其中,运算器和控制器放在一起就是我们通常所说的中央处理器,它的功能是执行各种运算和控制指令以及处理计算机软件中的数据。我们通常所说的程序实际上就是指令的集合,我们程序就是将一系列的指令按照某种方式组织到一起,然后通过这些指令去控制计算机做我们想让它做的事情。今天我们大多数时候使用的计算机,虽然它们的元器件做工越来越精密,处理能力越来越强大,但究其本质来说仍然属于[“冯·诺依曼结构”](https://zh.wikipedia.org/wiki/%E5%86%AF%C2%B7%E8%AF%BA%E4%BC%8A%E6%9B%BC%E7%BB%93%E6%9E%84)的计算机。“冯·诺依曼结构”有两个关键点一是指出要将存储设备与中央处理器分开二是提出了将数据以二进制方式编码。二进制是一种“逢二进一”的计数法跟我们人类使用的“逢十进一”的计数法没有实质性的区别人类因为有十根手指所以使用了十进制因为在数数时十根手指用完之后就只能进位了当然凡事都有例外玛雅人可能是因为长年光着脚的原因把脚趾头也算上了于是他们使用了二十进制的计数法在这种计数法的指导下玛雅人的历法就与我们平常使用的历法不一样而按照玛雅人的历法2012年是上一个所谓的“太阳纪”的最后一年而2013年则是新的“太阳纪”的开始后来这件事情被以讹传讹的方式误传为”2012年是玛雅人预言的世界末日“这种荒诞的说法今天我们可以大胆的猜测玛雅文明之所以发展缓慢估计也与使用了二十进制有关。对于计算机来说二进制在物理器件上来说是最容易实现的高电压表示1低电压表示0于是在“冯·诺依曼结构”的计算机都使用了二进制。虽然我们并不需要每个程序员都能够使用二进制的思维方式来工作但是了解二进制以及它与我们生活中的十进制之间的转换关系以及二进制与八进制和十六进制的转换关系还是有必要的。如果你对这一点不熟悉可以自行使用[维基百科](https://zh.wikipedia.org/wiki/%E4%BA%8C%E8%BF%9B%E5%88%B6)或者[百度百科](https://baike.baidu.com)科普一下。
> 提示:近期关于**量子计算机**的研究已经被推倒了风口浪尖量子计算机基于量子力学进行运算使用量子瞬移的方式来传递信息。2018年6月Intel宣布开发出新款量子芯片并通过了在接近绝对零度环境下的测试2019年1月IBM向全世界发布了首款商业化量子计算机。
> **说明**:近期关于**量子计算机**的研究已经被推倒了风口浪尖量子计算机基于量子力学进行运算使用量子瞬移的方式来传递信息。2018年6月Intel宣布开发出新款量子芯片并通过了在接近绝对零度环境下的测试2019年IBM和Google都推出了自己的量子计算机。
### 变量和类型
在程序设计中变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间变量的值可以被读取和修改这是所有计算和控制的基础。计算机能处理的数据有很多种类型除了数值之外还可以处理文本、图形、音频、视频等各种各样的数据那么不同的数据就需要定义不同的存储类型。Python中的数据类型很多而且也允许我们自定义新的数据类型这一点在后面会讲到我们先介绍几种常用的数据类型。
- 整型Python中可以处理任意大小的整数Python 2.x中有int和long两种类型的整数但这种区分对Python来说意义不大因此在Python 3.x中整数只有int这一种了而且支持二进制如`0b100`换算成十进制是4、八进制如`0o100`换算成十进制是64、十进制`100`)和十六进制(`0x100`换算成十进制是256的表示法。
- 整型Python中可以处理任意大小的整数Python 2.x中有`int``long`两种类型的整数但这种区分对Python来说意义不大因此在Python 3.x中整数只有int这一种了而且支持二进制如`0b100`换算成十进制是4、八进制如`0o100`换算成十进制是64、十进制`100`)和十六进制(`0x100`换算成十进制是256的表示法。
- 浮点型:浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如`123.456`)之外还支持科学计数法(如`1.23456e2`)。
- 字符串型:字符串是以单引号或双引号括起来的任意文本,比如`'hello'`和`"hello"`,字符串还有原始字符串表示法、字节字符串表示法、Unicode字符串表示法而且可以书写成多行的形式用三个单引号或三个双引号开头三个单引号或三个双引号结尾
- 布尔型:布尔值只有`True`、`False`两种值,要么是`True`,要么是`False`在Python中可以直接用`True`、`False`表示布尔值(请注意大小写),也可以通过布尔运算计算出来(例如`3 < 5``True``2 == 1``False`
- 复数型:形如`3+5j`,跟数学上的复数表示一样,唯一不同的是虚部的`i`换成了`j`。
- 复数型:形如`3+5j`,跟数学上的复数表示一样,唯一不同的是虚部的`i`换成了`j`。实际上,这个类型并不常用,大家了解一下就可以了。
#### 变量命名
@ -37,33 +37,59 @@
```Python
"""
使用变量保存数据并进行算术运算
使用变量保存数据并进行加减乘除运算
Version: 0.1
Author: 骆昊
"""
a = 321
b = 123
print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a // b)
print(a % b)
print(a ** b)
b = 12
print(a + b) # 333
print(a - b) # 309
print(a * b) # 3852
print(a / b) # 26.75
```
在Python中可以使用`type`函数对变量的类型进行检查。程序设计中函数的概念跟数学上函数的概念是一致的,数学上的函数相信大家并不陌生,它包括了函数名、自变量和因变量。如果暂时不理解这个概念也不要紧,我们会在后续的章节中专门讲解函数的定义和使用。
```Python
"""
使用input()函数获取键盘输入
使用int()进行类型转换
用占位符格式化输出的字符串
使用type()检查变量的类型
Version: 0.1
Author: 骆昊
"""
a = 100
b = 12.345
c = 1 + 5j
d = 'hello, world'
e = True
print(type(a)) # <class 'int'>
print(type(b)) # <class 'float'>
print(type(c)) # <class 'complex'>
print(type(d)) # <class 'str'>
print(type(e)) # <class 'bool'>
```
可以使用Python中内置的函数对变量类型进行转换。
- `int()`:将一个数值或字符串转换成整数,可以指定进制。
- `float()`:将一个字符串转换成浮点数。
- `str()`:将指定的对象转换成字符串形式,可以指定编码。
- `chr()`:将整数转换成该编码对应的字符串(一个字符)。
- `ord()`:将字符串(一个字符)转换成对应的编码(整数)。
下面的代码通过键盘输入两个整数来实现对两个整数的算术运算。
```Python
"""
使用input()函数获取键盘输入(字符串)
使用int()函数将输入的字符串转换成整数
使用print()函数输出带占位符的字符串
Version: 0.1
Author: 骆昊
"""
a = int(input('a = '))
b = int(input('b = '))
print('%d + %d = %d' % (a, b, a + b))
@ -75,38 +101,11 @@ print('%d %% %d = %d' % (a, b, a % b))
print('%d ** %d = %d' % (a, b, a ** b))
```
```Python
"""
使用type()检查变量的类型
Version: 0.1
Author: 骆昊
Date: 2018-02-27
"""
a = 100
b = 12.345
c = 1 + 5j
d = 'hello, world'
e = True
print(type(a))
print(type(b))
print(type(c))
print(type(d))
print(type(e))
```
在对变量类型进行转换时可以使用Python的内置函数。
- `int()`:将一个数值或字符串转换成整数,可以指定进制。
- `float()`:将一个字符串转换成浮点数。
- `str()`:将指定的对象转换成字符串形式,可以指定编码。
- `chr()`:将整数转换成该编码对应的字符串(一个字符)。
- `ord()`:将字符串(一个字符)转换成对应的编码(整数)。
> **说明**上面的print函数中输出的字符串使用了占位符语法其中`%d`是整数的占位符,`%f`是小数的占位符,`%%`表示百分号(因为百分号代表了占位符,所以带占位符的字符串中要表示百分号必须写成`%%`),字符串之后的`%`后面跟的变量值会替换掉占位符然后输出到终端中,运行上面的程序,看看程序执行结果就明白啦。
### 运算符
Python支持多种运算符下表大致按照优先级从高到低的顺序列出了所有的运算符我们会陆续使用到它们
Python支持多种运算符下表大致按照优先级从高到低的顺序列出了所有的运算符运算符的优先级指的是多个运算符同时出现时先做什么运算然后再做什么运算。除了我们之前已经用过的赋值运算符和算术运算符我们稍后会陆续讲到其他运算符的使用。
| 运算符 | 描述 |
| ------------------------------------------------------------ | ------------------------------ |
@ -127,61 +126,83 @@ Python支持多种运算符下表大致按照优先级从高到低的顺序
>**说明:** 在实际开发中,如果搞不清楚运算符的优先级,可以使用括号来确保运算的执行顺序。
下面的例子演示了运算符的使用。
#### 赋值运算符
赋值运算符应该是最为常见的运算符,它的作用是将右边的值赋给左边的变量。下面的例子演示了赋值运算符和复合赋值运算符的使用。
```Python
"""
运算符的使用
赋值运算符和复合赋值运算符
Version: 0.1
Author: 骆昊
"""
a = 10
b = 3
a += b # 相当于a = a + b
a *= a + 2 # 相当于a = a * (a + 2)
print(a) # 算一下这里会输出什么
```
a = 5
b = 10
c = 3
d = 4
e = 5
a += b
a -= c
a *= d
a /= e
print("a = ", a)
### 比较运算符和逻辑运算符
比较运算符有的地方也称为关系运算符,包括`==`、`!=`、`<`、`>`、`<=`、`>=`,我相信没有什么好解释的,大家一看就能懂,唯一需要提醒的是比较相等用的是`==`,请注意这个地方是两个等号,因为`=`是赋值运算符,我们在上面刚刚讲到过,`==`才是比较相等的比较运算符。比较运算符会产生布尔值,要么是`True`要么是`False`。
逻辑运算符有三个,分别是`and`、`or`和`not`。`and`字面意思是“而且”,所以`and`运算符会连接两个布尔值,如果两个布尔值都是`True`,那么运算的结果就是`True`;左右两边的布尔值有一个是`False`,最终的运算结果就是`False`。相信大家已经想到了,如果`and`左边的布尔值是`False`,不管右边的布尔值是什么,最终的结果都是`False`,所以在做运算的时候右边的值会被跳过(短路处理),这也就意味着在`and`运算符左边为`False`的情况下,右边的表达式根本不会执行。`or`字面意思是“或者”,所以`or`运算符也会连接两个布尔值,如果两个布尔值有任意一个是`True`,那么最终的结果就是`True`。当然,`or`运算符也是有短路功能的,在它左边的布尔值为`True`的情况下,右边的表达式根本不会执行。`not`运算符的后面会跟上一个布尔值,它的作用是得到与该布尔值相反的值,也就是说,后面的布尔值如果是`True`运算结果就是`False`,而后面的布尔值如果是`False`则运算结果就是`True`。
```Python
"""
比较运算符和逻辑运算符的使用
Version: 0.1
Author: 骆昊
"""
flag0 = 1 == 1
flag1 = 3 > 2
flag2 = 2 < 1
flag3 = flag1 and flag2
flag4 = flag1 or flag2
flag5 = not flag1
print("flag1 = ", flag1)
print("flag2 = ", flag2)
print("flag3 = ", flag3)
print("flag4 = ", flag4)
print("flag5 = ", flag5)
print(flag1 is True)
print(flag2 is not False)
flag5 = not (1 != 2)
print('flag0 =', flag0) # flag0 = True
print('flag1 =', flag1) # flag1 = True
print('flag2 =', flag2) # flag2 = False
print('flag3 =', flag3) # flag3 = False
print('flag4 =', flag4) # flag4 = True
print('flag5 =', flag5) # flag5 = False
```
> **说明**:比较运算符的优先级高于赋值运算符,所以`flag0 = 1 == 1`先做`1 == 1`产生布尔值`True`,再将这个值赋值给变量`flag0`。`print`函数可以输出多个值,多个值之间可以用`,`进行分隔,输出的内容之间默认以空格分开。
### 练习
#### 练习1华氏温度转摄氏温度。
#### 练习1华氏温度转换为摄氏温度。
> 提示:华氏温度到摄氏温度的转换公式为:$C=(F - 32) \div 1.8$。
参考答案:
```Python
"""
将华氏温度转换为摄氏温度
F = 1.8C + 32
Version: 0.1
Author: 骆昊
"""
f = float(input('请输入华氏温度: '))
c = (f - 32) / 1.8
print('%.1f华氏度 = %.1f摄氏度' % (f, c))
```
> **说明**:在使用`print`函数输出时,也可以对字符串内容进行格式化处理,上面`print`函数中的字符串`%1.f`是一个占位符,稍后会由一个`float`类型的变量值替换掉它。同理,如果字符串中有`%d`,后面可以用一个`int`类型的变量值替换掉它,而`%s`会被字符串的值替换掉。除了这种格式化字符串的方式外,还可以用下面的方式来格式化字符串,其中`{f:.1f}`和`{c:.1f}`可以先看成是`{f}`和`{c}`,表示输出时会用变量`f`和变量`c`的值替换掉这两个占位符,后面的`:.1f`表示这是一个浮点数小数点后保留1位有效数字。
>
> ```Python
> print(f'{f:.1f}华氏度 = {c:.1f}摄氏度')
> ```
#### 练习2输入圆的半径计算计算周长和面积。
参考答案:
```Python
"""
输入半径计算圆的周长和面积
@ -189,18 +210,17 @@ print('%.1f华氏度 = %.1f摄氏度' % (f, c))
Version: 0.1
Author: 骆昊
"""
import math
radius = float(input('请输入圆的半径: '))
perimeter = 2 * math.pi * radius
area = math.pi * radius * radius
perimeter = 2 * 3.1416 * radius
area = 3.1416 * radius * radius
print('周长: %.2f' % perimeter)
print('面积: %.2f' % area)
```
#### 练习3输入年份判断是不是闰年。
参考答案:
```Python
"""
输入年份 如果是闰年输出True 否则输出False
@ -208,11 +228,11 @@ print('面积: %.2f' % area)
Version: 0.1
Author: 骆昊
"""
year = int(input('请输入年份: '))
# 如果代码太长写成一行不便于阅读 可以使用\或()折行
is_leap = (year % 4 == 0 and year % 100 != 0 or
year % 400 == 0)
# 如果代码太长写成一行不便于阅读 可以使用\对代码进行折行
is_leap = year % 4 == 0 and year % 100 != 0 or \
year % 400 == 0
print(is_leap)
```
> **说明**:比较运算符会产生布尔值,而逻辑运算符`and`和`or`会对这些布尔值进行组合,最终也是得到一个布尔值,闰年输出`True`,平年输出`False`。

View File

@ -15,21 +15,18 @@
Version: 0.1
Author: 骆昊
"""
username = input('请输入用户名: ')
password = input('请输入口令: ')
# 如果希望输入口令时 终端中没有回显 可以使用getpass模块的getpass函数
# import getpass
# password = getpass.getpass('请输入口令: ')
# 用户名是admin且密码是123456则身份验证成功否则身份验证失败
if username == 'admin' and password == '123456':
print('身份验证成功!')
else:
print('身份验证失败!')
```
唯一需要说明的是和C/C++、Java等语言不同Python中没有用花括号来构造代码块而是使用了缩进的方式来设置代码的层次结构,如果`if`条件成立的情况下需要执行多条语句,只要保持多条语句具有相同的缩进就可以了,换句话说连续的代码如果又保持了相同的缩进那么它们属于同一个代码块,相当于是一个执行的整体。
需要说明的是和C/C++、Java等语言不同Python中没有用花括号来构造代码块而是**使用了缩进的方式来表示代码的层次结构**,如果`if`条件成立的情况下需要执行多条语句,只要保持多条语句具有相同的缩进就可以了。换句话说**连续的代码如果又保持了相同的缩进那么它们属于同一个代码块**,相当于是一个执行的整体。**缩进**可以使用任意数量的空格,但**通常使用4个空格**,建议大家**不要使用制表键**或者**设置你的代码编辑工具自动将制表键变成4个空格**。
当然如果要构造出更多的分支,可以使用`if…elif…else…`结构,例如下面的分段函数求值。
当然如果要构造出更多的分支,可以使用`if...elif...else...`结构或者嵌套的`if...else...`结构,下面的代码演示了如何利用多分支结构实现分段函数求值。
![$$f(x)=\begin{cases} 3x-5&\text{(x>1)}\\x+2&\text{(-1}\leq\text{x}\leq\text{1)}\\5x+3&\text {(x<-1)}\end{cases}$$](./res/formula_1.png)
@ -83,7 +80,9 @@ print('f(%.2f) = %.2f' % (x, y))
### 练习
#### 练习1英制单位与公制单位互换
#### 练习1英制单位英寸与公制单位厘米互换。
参考答案:
```Python
"""
@ -92,7 +91,6 @@ print('f(%.2f) = %.2f' % (x, y))
Version: 0.1
Author: 骆昊
"""
value = float(input('请输入长度: '))
unit = input('请输入单位: ')
if unit == 'in' or unit == '英寸':
@ -103,50 +101,19 @@ else:
print('请输入有效的单位')
```
#### 练习2掷骰子决定做什么
#### 练习2百分制成绩转换为等级制成绩。
> **要求**如果输入的成绩在90分以上含90分输出A80分-90分不含90分输出B70分-80分不含80分输出C60分-70分不含70分输出D60分以下输出E。
参考答案:
```Python
"""
掷骰子决定做什么事情
百分制成绩转换为等级制成绩
Version: 0.1
Author: 骆昊
"""
from random import randint
face = randint(1, 6)
if face == 1:
result = '唱首歌'
elif face == 2:
result = '跳个舞'
elif face == 3:
result = '学狗叫'
elif face == 4:
result = '做俯卧撑'
elif face == 5:
result = '念绕口令'
else:
result = '讲冷笑话'
print(result)
```
> **说明:** 上面的代码中使用了random模块的randint函数生成指定范围的随机数来模拟掷骰子。
#### 练习3百分制成绩转等级制
```Python
"""
百分制成绩转等级制成绩
90分以上 --> A
80分~89分 --> B
70分~79分 --> C
60分~69分 --> D
60分以下 --> E
Version: 0.1
Author: 骆昊
"""
score = float(input('请输入成绩: '))
if score >= 90:
grade = 'A'
@ -160,71 +127,27 @@ else:
grade = 'E'
print('对应的等级是:', grade)
```
#### 练习4输入三条边长如果能构成三角形就计算周长和面积
#### 练习3输入三条边长如果能构成三角形就计算周长和面积。
参考答案:
```Python
"""
判断输入的边长能否构成三角形
如果能则计算出三角形的周长和面积
判断输入的边长能否构成三角形,如果能则计算出三角形的周长和面积
Version: 0.1
Author: 骆昊
"""
import math
a = float(input('a = '))
b = float(input('b = '))
c = float(input('c = '))
if a + b > c and a + c > b and b + c > a:
print('周长: %f' % (a + b + c))
p = (a + b + c) / 2
area = math.sqrt(p * (p - a) * (p - b) * (p - c))
area = (p * (p - a) * (p - b) * (p - c)) ** 0.5
print('面积: %f' % (area))
else:
print('不能构成三角形')
```
> **说明:** 上面的代码中使用了`math`模块的`sqrt`函数来计算平方根。用边长计算三角形面积的公式叫做[海伦公式](https://zh.wikipedia.org/zh-hans/海伦公式)。
> **说明:** 上面使用的通过边长计算三角形面积的公式叫做[海伦公式](https://zh.wikipedia.org/zh-hans/海伦公式)。
#### 练习5个人所得税计算器。
```Python
"""
输入月收入和五险一金计算个人所得税
Version: 0.1
Author: 骆昊
"""
salary = float(input('本月收入: '))
insurance = float(input('五险一金: '))
diff = salary - insurance - 3500
if diff <= 0:
rate = 0
deduction = 0
elif diff < 1500:
rate = 0.03
deduction = 0
elif diff < 4500:
rate = 0.1
deduction = 105
elif diff < 9000:
rate = 0.2
deduction = 555
elif diff < 35000:
rate = 0.25
deduction = 1005
elif diff < 55000:
rate = 0.3
deduction = 2755
elif diff < 80000:
rate = 0.35
deduction = 5505
else:
rate = 0.45
deduction = 13505
tax = abs(diff * rate - deduction)
print('个人所得税: ¥%.2f元' % tax)
print('实际到手收入: ¥%.2f元' % (diff + 3500 - tax))
```
>**说明:** 上面的代码中使用了Python内置的`abs()`函数取绝对值来处理`-0`的问题。

View File

@ -2,9 +2,9 @@
### 应用场景
如果在程序中我们需要重复的执行某条或某些指令,例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向奔跑的指令。当然你可能已经注意到了刚才的描述中其实不仅仅有需要重复的动作还有我们上一个章节讲到的分支结构。再举一个简单的例子比如在我们的程序中要实现每隔1秒中在屏幕上打印一个&quot;hello, world&quot;这样的字符串并持续一个小时,我们肯定不能够将`print('hello, world')`这句代码写上3600遍如果真的需要这样做那么编程的工作就太无聊了。因此我们还需要了解一下循环结构有了循环结构我们就可以轻松的控制某件事或者某些事重复、重复、再重复的去执行
我们在写程序的时候,一定会遇到需要重复执行某条或某些指令的场景。例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向移动的指令。在这个场景中让机器人向球门方向移动就是一个需要重复的动作当然这里还会用到上一课讲的分支结构来判断机器人是否持球以及是否进入射门范围。再举一个简单的例子如果要实现每隔1秒中在屏幕上打印一次“hello, world”并持续打印一个小时我们肯定不能够直接把`print('hello, world')`这句代码写3600遍这里同样需要循环结构
在Python中构造循环结构有两种做法一种是`for-in`循环,一种是`while`循环。
循环结构就是程序中控制某条或某些指令重复执行的结构。在Python中构造循环结构有两种做法一种是`for-in`循环,一种是`while`循环。
### for-in循环
@ -24,11 +24,12 @@ for x in range(101):
print(sum)
```
需要说明的是上面代码中的`range`类型,`range`可以用来产生一个不变的数值序列,而且这个序列通常都是用在循环中的,例如
需要说明的是上面代码中的`range(1, 101)`可以用来构造一个从1到100的范围当我们把这样一个范围放到`for-in`循环中,就可以通过前面的循环变量`x`依次取出从1到100的整数。当然`range`的用法非常灵活,下面给出了一个例子
- `range(101)`可以产生一个0到100的整数序列。
- `range(1, 100)`可以产生一个1到99的整数序列。
- `range(1, 100, 2)`可以产生一个1到99的奇数序列其中的2是步长即数值序列的增量。
- `range(101)`可以用来产生0到100范围的整数需要注意的是取不到101。
- `range(1, 101)`可以用来产生1到100范围的整数相当于前面是闭区间后面是开区间。
- `range(1, 101, 2)`可以用来产生1到100的奇数其中2是步长即每次数值递增的值。
- `range(100, 0, -2)`可以用来产生100到1的偶数其中-2是步长即每次数字递减的值。
知道了这一点我们可以用下面的代码来实现1~100之间的偶数求和。
@ -46,7 +47,7 @@ for x in range(2, 101, 2):
print(sum)
```
也可以通过在循环中使用分支结构的方式来实现相同的功能,代码如下所示。
当然,也可以通过在循环中使用分支结构的方式来实现相同的功能,代码如下所示。
```Python
"""
@ -63,20 +64,21 @@ for x in range(1, 101):
print(sum)
```
> **说明**:相较于上面直接跳过奇数的做法,下面这种做法很明显并不是很好的选择。
### while循环
如果要构造不知道具体循环次数的循环结构,我们推荐使用`while`循环。`while`循环通过一个能够产生或转换出`bool`值的表达式来控制循环,表达式的值为`True`循环继续,表达式的值为`False`循环结束。下面我们通过一个“猜数字”的小游戏计算机出一个1~100之间的随机数人输入自己猜的数字计算机给出对应的提示信息直到人猜出计算机出的数字来看看如何使用`while`循环。
如果要构造不知道具体循环次数的循环结构,我们推荐使用`while`循环。`while`循环通过一个能够产生或转换出`bool`值的表达式来控制循环,表达式的值为`True`则继续循环;表达式的值为`False`则结束循环。
下面我们通过一个“猜数字”的小游戏来看看如何使用`while`循环。猜数字游戏的规则是计算机出一个1到100之间的随机数玩家输入自己猜的数字计算机给出对应的提示信息大一点、小一点或猜对了如果玩家猜中了数字计算机提示用户一共猜了多少次游戏结束否则游戏继续。
```Python
"""
猜数字游戏
计算机出一个1~100之间的随机数由人来猜
计算机根据人猜的数字分别给出提示大一点/小一点/猜对了
Version: 0.1
Author: 骆昊
"""
import random
answer = random.randint(1, 100)
@ -96,7 +98,7 @@ if counter > 7:
print('你的智商余额明显不足')
```
> **说明:** 上面的代码中使用了`break`关键字来提前终止循环,需要注意的是`break`只能终止它所在的那个循环,这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。除了`break`之外,还有另一个关键字是`continue`,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。
上面的代码中使用了`break`关键字来提前终止循环,需要注意的是`break`只能终止它所在的那个循环,这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。除了`break`之外,还有另一个关键字是`continue`,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。
和分支结构一样,循环结构也是可以嵌套的,也就是说在循环中还可以构造循环结构。下面的例子演示了如何通过嵌套的循环来输出一个九九乘法表。
@ -116,7 +118,11 @@ for i in range(1, 10):
### 练习
#### 练习1输入一个数判断是不是素数。
#### 练习1输入一个正整数判断是不是素数。
> **提示**素数指的是只能被1和自身整除的大于1的整数。
参考答案:
```Python
"""
@ -141,11 +147,15 @@ else:
print('%d不是素数' % num)
```
#### 练习2输入两个正整数计算最大公约数和最小公倍数。
#### 练习2输入两个正整数计算它们的最大公约数和最小公倍数。
> **提示**:两个数的最大公约数是两个数的公共因子中最大的那个数;两个数的最小公倍数则是能够同时被两个数整除的最小的那个数。
参考答案:
```Python
"""
输入两个正整数计算最大公约数和最小公倍数
输入两个正整数计算它们的最大公约数和最小公倍数
Version: 0.1
Author: 骆昊
@ -154,8 +164,11 @@ Date: 2018-03-01
x = int(input('x = '))
y = int(input('y = '))
# 如果x大于y就交换x和y的值
if x > y:
# 通过下面的操作将y的值赋给x, 将x的值赋给y
x, y = y, x
# 从两个数中较的数开始做递减的循环
for factor in range(x, 0, -1):
if x % factor == 0 and y % factor == 0:
print('%d和%d的最大公约数是%d' % (x, y, factor))
@ -163,29 +176,37 @@ for factor in range(x, 0, -1):
break
```
#### 练习3打印三角形图案。
```Python
"""
打印各种三角形图案
#### 练习3打印如下所示的三角形图案。
```
*
**
***
****
*****
```
```
*
**
***
****
*****
```
```
*
***
*****
*******
*********
```
参考答案:
```Python
"""
打印三角形图案
Version: 0.1
Author: 骆昊

View File

@ -1,13 +1,130 @@
## 构造程序逻辑
分支和循环结构会帮助我们将程序中逻辑建立起来,将来我们的程序无论简单复杂,都是由顺序结构、分支结构、循环结构构成的。对于编程语言的初学者来说,首先要锻炼的是将人类自然语言描述的解决问题的步骤和方法翻译成代码的能力,其次就是熟练的运用之前学过的运算符、表达式以及最近的两个章节讲解的分支结构和循环结构的知识。有了这些基本的能力才能够通过计算机程序去解决各种各样的现实问题。所以,开始做练习吧!
学完前面的几个章节后我觉得有必要在这里带大家做一些练习来巩固之前所学的知识虽然迄今为止我们学习的内容只是Python的冰山一角但是这些内容已经足够我们来构建程序中的逻辑。对于编程语言的初学者来说在学习了Python的核心语言元素变量、类型、运算符、表达式、分支结构、循环结构等之后必须做的一件事情就是尝试用所学知识去解决现实中的问题换句话说就是锻炼自己把用人类自然语言描述的算法解决问题的方法和步骤翻译成Python代码的能力而这件事情必须通过大量的练习才能达成。
### 练习清单
我们在本章为大家整理了一些经典的案例和习题希望通过这些例子一方面帮助大家巩固之前所学的Python知识另一方面帮助大家了解如何建立程序中的逻辑以及如何运用一些简单的算法解决现实中的问题。
1. 寻找[“水仙花数”](https://baike.baidu.com/item/%E6%B0%B4%E4%BB%99%E8%8A%B1%E6%95%B0)。
2. 寻找[“完美数”](https://baike.baidu.com/item/%E5%AE%8C%E5%85%A8%E6%95%B0/370913)。
3. [“百钱百鸡”](https://baike.baidu.com/item/%E7%99%BE%E9%B8%A1%E7%99%BE%E9%92%B1/5857320)问题。
4. 生成[“斐波拉切数列”](https://baike.baidu.com/item/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97/99145)。
5. Craps赌博游戏。
### 经典的例子
> **提示**练习的参考答案在code/Day05目录下。
1. 寻找**水仙花数**。
> **说明**水仙花数也被称为超完全数字不变数、自恋数、自幂数、阿姆斯特朗数它是一个3位数该数字每个位上数字的立方之和正好等于它本身例如$1^3 + 5^3+ 3^3=153$。
```Python
"""
找出所有水仙花数
Version: 0.1
Author: 骆昊
"""
for num in range(100, 1000):
low = num % 10
mid = num // 10 % 10
high = num // 100
if num == low ** 3 + mid ** 3 + high ** 3:
print(num)
```
在上面的代码中我们通过整除和求模运算分别找出了一个三位数的个位、十位和百位这种小技巧在实际开发中还是常用的。用类似的方法我们还可以实现将一个正整数反转例如将12345变成54321代码如下所示。
```Python
"""
正整数的反转
Version: 0.1
Author: 骆昊
"""
num = int(input('num = '))
reversed_num = 0
while num > 0:
reversed_num = reversed_num * 10 + num % 10
num //= 10
print(reversed_num)
```
2. **百钱百鸡**问题。
> **说明**:百钱百鸡是我国古代数学家[张丘建](https://baike.baidu.com/item/%E5%BC%A0%E4%B8%98%E5%BB%BA/10246238)在《算经》一书中提出的数学问题鸡翁一值钱五鸡母一值钱三鸡雏三值钱一。百钱买百鸡问鸡翁、鸡母、鸡雏各几何翻译成现代文是公鸡5元一只母鸡3元一只小鸡1元三只用100块钱买一百只鸡问公鸡、母鸡、小鸡各有多少只
```Python
"""
《百钱百鸡》问题
Version: 0.1
Author: 骆昊
"""
for x in range(0, 20):
for y in range(0, 33):
z = 100 - x - y
if 5 * x + 3 * y + z / 3 == 100:
print('公鸡: %d只, 母鸡: %d只, 小鸡: %d只' % (x, y, z))
```
上面使用的方法叫做**穷举法**,也称为**暴力搜索法**,这种方法通过一项一项的列举备选解决方案中所有可能的候选项并检查每个候选项是否符合问题的描述,最终得到问题的解。这种方法看起来比较笨拙,但对于运算能力非常强大的计算机来说,通常都是一个可行的甚至是不错的选择,而且问题的解如果存在,这种方法一定能够找到它。
3. **CRAPS赌博游戏**
> **说明**CRAPS又称花旗骰是美国拉斯维加斯非常受欢迎的一种的桌上赌博游戏。该游戏使用两粒骰子玩家通过摇两粒骰子获得点数进行游戏。简单的规则是玩家第一次摇骰子如果摇出了7点或11点玩家胜玩家第一次如果摇出2点、3点或12点庄家胜其他点数玩家继续摇骰子如果玩家摇出了7点庄家胜如果玩家摇出了第一次摇的点数玩家胜其他点数玩家继续要骰子直到分出胜负。
```Python
"""
Craps赌博游戏
我们设定玩家开始游戏时有1000元的赌注
游戏结束的条件是玩家输光所有的赌注
Version: 0.1
Author: 骆昊
"""
from random import randint
money = 1000
while money > 0:
print('你的总资产为:', money)
needs_go_on = False
while True:
debt = int(input('请下注: '))
if 0 < debt <= money:
break
first = randint(1, 6) + randint(1, 6)
print('玩家摇出了%d点' % first)
if first == 7 or first == 11:
print('玩家胜!')
money += debt
elif first == 2 or first == 3 or first == 12:
print('庄家胜!')
money -= debt
else:
needs_go_on = True
while needs_go_on:
needs_go_on = False
current = randint(1, 6) + randint(1, 6)
print('玩家摇出了%d点' % current)
if current == 7:
print('庄家胜')
money -= debt
elif current == first:
print('玩家胜')
money += debt
else:
needs_go_on = True
print('你破产了, 游戏结束!')
```
###有用的练习
1. 生成**斐波那契数列**的前20个数。
> **说明**斐波那契数列Fibonacci sequence又称黄金分割数列是意大利数学家莱昂纳多·斐波那契Leonardoda Fibonacci在《计算之书》中提出一个在理想假设条件下兔子成长率的问题而引入的数列所以这个数列也被戏称为&quot;兔子数列&quot;。斐波那契数列的特点是数列的前两个数都是1从第三个数开始每个数都是它前面两个数的和形如1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...。斐波那契数列在现代物理、准晶体结构、化学等领域都有直接的应用。
2. 找出10000以内的**完美数**。
> **说明**完美数又称为完全数或完备数它的所有的真因子即除了自身以外的因子的和即因子函数恰好等于它本身。例如6$6=1+2+3$和28$28=1+2+4+7+14$)就是完美数。完美数有很多神奇的特性,有兴趣的可以自行了解。
3. 输出**100以内所有的素数**。
> **说明**素数指的是只能被1和自身整除的正整数不包括1
上面练习的参考答案在本章对应的代码目录中,如果需要帮助请读者自行查看参考答案。

View File

@ -13,8 +13,10 @@
```Python
"""
输入M和N计算C(M,N)
"""
Version: 0.1
Author: 骆昊
"""
m = int(input('m = '))
n = int(input('n = '))
fm = 1
@ -23,10 +25,10 @@ for num in range(1, m + 1):
fn = 1
for num in range(1, n + 1):
fn *= num
fmn = 1
fm_n = 1
for num in range(1, m - n + 1):
fmn *= num
print(fm // fn // fmn)
fm_n *= num
print(fm // fn // fm_n)
```
### 函数的作用
@ -40,13 +42,14 @@ print(fm // fn // fmn)
在了解了如何定义函数后,我们可以对上面的代码进行重构,所谓重构就是在不影响代码执行结果的前提下对代码的结构进行调整,重构之后的代码如下所示。
```Python
def factorial(num):
"""
求阶乘
:param num: 非负整数
:return: num的阶乘
"""
"""
输入M和N计算C(M,N)
Version: 0.1
Author: 骆昊
"""
def fac(num):
"""求阶乘"""
result = 1
for n in range(1, num + 1):
result *= n
@ -56,27 +59,22 @@ def factorial(num):
m = int(input('m = '))
n = int(input('n = '))
# 当需要计算阶乘的时候不用再写循环求阶乘而是直接调用已经定义好的函数
print(factorial(m) // factorial(n) // factorial(m - n))
print(fac(m) // fac(n) // fac(m - n))
```
> **说明:** Python的math模块中其实已经有一个factorial函数了事实上要计算阶乘可以直接使用这个现成的函数而不用自己定义。下面例子中的某些函数其实Python中也是内置了我们这里是为了讲解函数的定义和使用才把它们又实现了一遍实际开发中不建议做这种低级的重复性的工作
> **说明:** Python的`math`模块中其实已经有一个名为`factorial`函数实现了阶乘运算事实上求阶乘并不用自己定义函数。下面的例子中我们讲的函数在Python标准库已经实现过了我们这里是为了讲解函数的定义和使用才把它们又实现了一遍**实际开发中并不建议做这种低级的重复劳动**
### 函数的参数
函数是绝大多数编程语言中都支持的一个代码的“构建块”但是Python中的函数与其他语言中的函数还是有很多不太相同的地方其中一个显著的区别就是Python对函数参数的处理。在Python中函数的参数可以有默认值也支持使用可变参数所以Python并不需要像其他语言一样支持[函数的重载](https://zh.wikipedia.org/wiki/%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD),因为我们在定义一个函数的时候可以让它有多种不同的使用方式,下面是两个小例子。
函数是绝大多数编程语言中都支持的一个代码的&quot;构建块&quot;但是Python中的函数与其他语言中的函数还是有很多不太相同的地方其中一个显著的区别就是Python对函数参数的处理。在Python中函数的参数可以有默认值也支持使用可变参数所以Python并不需要像其他语言一样支持[函数的重载](https://zh.wikipedia.org/wiki/%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD),因为我们在定义一个函数的时候可以让它有多种不同的使用方式,下面是两个小例子。
```Python
from random import randint
def roll_dice(n=2):
"""
摇色子
:param n: 色子的个数
:return: n颗色子点数之和
"""
"""摇色子"""
total = 0
for _ in range(n):
total += randint(1, 6)
@ -84,6 +82,7 @@ def roll_dice(n=2):
def add(a=0, b=0, c=0):
"""三个数相加"""
return a + b + c
@ -105,7 +104,6 @@ print(add(c=50, a=100, b=200))
```Python
# 在参数名前面的*表示args是一个可变参数
# 即在调用add函数时可以传入0个或多个参数
def add(*args):
total = 0
for val in args:
@ -113,6 +111,7 @@ def add(*args):
return total
# 在调用add函数时可以传入0个或多个参数
print(add())
print(add(1))
print(add(1, 2))
@ -139,21 +138,21 @@ foo()
当然上面的这种情况我们很容易就能避免,但是如果项目是由多人协作进行团队开发的时候,团队中可能有多个程序员都定义了名为`foo`的函数那么怎么解决这种命名冲突呢答案其实很简单Python中每个文件就代表了一个模块module我们在不同的模块中可以有同名的函数在使用函数的时候我们通过`import`关键字导入指定的模块就可以区分到底要使用的是哪个模块中的`foo`函数,代码如下所示。
module1.py
`module1.py`
```Python
def foo():
print('hello, world!')
```
module2.py
`module2.py`
```Python
def foo():
print('goodbye, world!')
```
test.py
`test.py`
```Python
from module1 import foo
@ -169,7 +168,7 @@ foo()
也可以按照如下所示的方式来区分到底要使用哪一个`foo`函数。
test.py
`test.py`
```Python
import module1 as m1
@ -181,7 +180,7 @@ m2.foo()
但是如果将代码写成了下面的样子,那么程序中调用的是最后导入的那个`foo`因为后导入的foo覆盖了之前导入的`foo`。
test.py
`test.py`
```Python
from module1 import foo
@ -191,7 +190,7 @@ from module2 import foo
foo()
```
test.py
`test.py`
```Python
from module2 import foo
@ -201,9 +200,9 @@ from module1 import foo
foo()
```
需要说明的是如果我们导入的模块除了定义函数之外还中有可以执行代码那么Python解释器在导入这个模块时就会执行这些代码事实上我们可能并不希望如此因此如果我们在模块中编写了执行代码最好是将这些执行代码放入如下所示的条件中这样的话除非直接运行该模块if条件下的这些代码是不会执行的因为只有直接执行的模块的名字才是“\_\_main\_\_”
需要说明的是如果我们导入的模块除了定义函数之外还中有可以执行代码那么Python解释器在导入这个模块时就会执行这些代码事实上我们可能并不希望如此因此如果我们在模块中编写了执行代码最好是将这些执行代码放入如下所示的条件中这样的话除非直接运行该模块if条件下的这些代码是不会执行的因为只有直接执行的模块的名字才是&quot;\_\_main\_\_&quot;
module3.py
`module3.py`
```Python
def foo():
@ -223,7 +222,7 @@ if __name__ == '__main__':
bar()
```
test.py
`test.py`
```Python
import module3
@ -235,8 +234,11 @@ import module3
#### 练习1实现计算求最大公约数和最小公倍数的函数。
参考答案:
```Python
def gcd(x, y):
"""求最大公约数"""
(x, y) = (y, x) if x > y else (x, y)
for factor in range(x, 0, -1):
if x % factor == 0 and y % factor == 0:
@ -244,13 +246,17 @@ def gcd(x, y):
def lcm(x, y):
"""求最小公倍数"""
return x * y // gcd(x, y)
```
#### 练习2实现判断一个数是不是回文数的函数。
参考答案:
```Python
def is_palindrome(num):
"""判断一个数是不是回文数"""
temp = num
total = 0
while temp > 0:
@ -261,9 +267,12 @@ def is_palindrome(num):
#### 练习3实现判断一个数是不是素数的函数。
参考答案:
```Python
def is_prime(num):
for factor in range(2, num):
"""判断一个数是不是素数"""
for factor in range(2, int(num ** 0.5) + 1):
if num % factor == 0:
return False
return True if num != 1 else False
@ -271,6 +280,8 @@ def is_prime(num):
#### 练习4写一个程序判断输入的正整数是不是回文素数。
参考答案:
```Python
if __name__ == '__main__':
num = int(input('请输入正整数: '))
@ -278,7 +289,9 @@ if __name__ == '__main__':
print('%d是回文素数' % num)
```
通过上面的程序可以看出,当我们将代码中重复出现的和相对独立的功能抽取成函数后,我们可以组合使用这些函数来解决更为复杂的问题,这也是我们为什么要定义和使用函数的一个非常重要的原因。
> **注意**:通过上面的程序可以看出,当我们**将代码中重复出现的和相对独立的功能抽取成函数**后,我们可以**组合使用这些函数**来解决更为复杂的问题,这也是我们为什么要定义和使用函数的一个非常重要的原因。
### 变量的作用域
最后我们来讨论一下Python中有关变量作用域的问题。
@ -286,7 +299,8 @@ if __name__ == '__main__':
def foo():
b = 'hello'
def bar(): # Python中可以在函数内部再定义函数
# Python中可以在函数内部再定义函数
def bar():
c = True
print(a)
print(b)
@ -302,7 +316,7 @@ if __name__ == '__main__':
foo()
```
上面的代码能够顺利的执行并且打印出100和“hello”,但我们注意到了,在`bar`函数的内部并没有定义`a`和`b`两个变量,那么`a`和`b`是从哪里来的。我们在上面代码的`if`分支中定义了一个变量`a`这是一个全局变量global variable属于全局作用域因为它没有定义在任何一个函数中。在上面的`foo`函数中我们定义了变量`b`这是一个定义在函数中的局部变量local variable属于局部作用域在`foo`函数的外部并不能访问到它;但对于`foo`函数内部的`bar`函数来说,变量`b`属于嵌套作用域,在`bar`函数中我们是可以访问到它的。`bar`函数中的变量`c`属于局部作用域,在`bar`函数之外是无法访问的。事实上Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索前三者我们在上面的代码中已经看到了所谓的“内置作用域”就是Python内置的那些隐含标识符`min`、`len`等都属于内置作用域)
上面的代码能够顺利的执行并且打印出100、hello和True,但我们注意到了,在`bar`函数的内部并没有定义`a`和`b`两个变量,那么`a`和`b`是从哪里来的。我们在上面代码的`if`分支中定义了一个变量`a`这是一个全局变量global variable属于全局作用域因为它没有定义在任何一个函数中。在上面的`foo`函数中我们定义了变量`b`这是一个定义在函数中的局部变量local variable属于局部作用域在`foo`函数的外部并不能访问到它;但对于`foo`函数内部的`bar`函数来说,变量`b`属于嵌套作用域,在`bar`函数中我们是可以访问到它的。`bar`函数中的变量`c`属于局部作用域,在`bar`函数之外是无法访问的。事实上Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索前三者我们在上面的代码中已经看到了所谓的“内置作用域”就是Python内置的那些标识符,我们之前用过的`input`、`print`、`int`等都属于内置作用域
再看看下面这段代码,我们希望通过函数调用修改全局变量`a`的值,但实际上下面的代码是做不到的。
@ -335,9 +349,9 @@ if __name__ == '__main__':
我们可以使用`global`关键字来指示`foo`函数中的变量`a`来自于全局作用域,如果全局作用域中没有`a`,那么下面一行的代码就会定义变量`a`并将其置于全局作用域。同理,如果我们希望函数内部的函数能够修改嵌套作用域中的变量,可以使用`nonlocal`关键字来指示变量来自于嵌套作用域,请大家自行试验。
在实际开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被[垃圾回收](https://zh.wikipedia.org/wiki/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8))。事实上,减少对全局变量的使用,也是降低代码之间耦合度的一个重要举措,同时也是对[迪米特法则](https://zh.wikipedia.org/zh-hans/%E5%BE%97%E5%A2%A8%E5%BF%92%E8%80%B3%E5%AE%9A%E5%BE%8B)的践行。减少全局变量的使用就意味着我们应该尽量让变量的作用域在函数的内部,但是如果我们希望将一个局部变量的生命周期延长,使其在函数调用结束后依然可以访问,这时候就需要使用[闭包](https://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)),这个我们在后续的内容中进行讲解。
在实际开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被[垃圾回收](https://zh.wikipedia.org/wiki/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8))。事实上,减少对全局变量的使用,也是降低代码之间耦合度的一个重要举措,同时也是对[迪米特法则](https://zh.wikipedia.org/zh-hans/%E5%BE%97%E5%A2%A8%E5%BF%92%E8%80%B3%E5%AE%9A%E5%BE%8B)的践行。减少全局变量的使用就意味着我们应该尽量让变量的作用域在函数的内部,但是如果我们希望将一个局部变量的生命周期延长,使其在定义它的函数调用结束后依然可以使用它的值,这时候就需要使用[闭包](https://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)),这个我们在后续的内容中进行讲解。
> **说明:** 很多人经常会将“闭包”一词和[“匿名函数”](https://zh.wikipedia.org/wiki/%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0)混为一谈,但实际上它们是不同的概念,如果想提前了解这个概念,推荐看看[维基百科](https://zh.wikipedia.org/wiki/)或者[知乎](https://www.zhihu.com/)上对这个概念的讨论。
> **说明:** 很多人经常会将“闭包”和[“匿名函数”](https://zh.wikipedia.org/wiki/%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0)混为一谈,但实际上它们并不是一回事,如果想了解这个概念,可以看看[维基百科](https://zh.wikipedia.org/wiki/)的解释或者[知乎](https://www.zhihu.com/)上对这个概念的讨论。
说了那么多其实结论很简单从现在开始我们可以将Python代码按照下面的格式进行书写这一点点的改进其实就是在我们理解了函数和作用域的基础上跨出的巨大的一步。

View File

@ -2,185 +2,249 @@
### 使用字符串
第二次世界大战促使了现代电子计算机的诞生,最初的目的用计算机来快速的完成导弹弹道的计算因此在计算机刚刚诞生的那个年代计算机处理的信息基本上都是数值型的信息而世界上的第一台电子计算机ENIAC每秒钟能够完成约5000次浮点运算。随着时间的推移虽然数值运算仍然是计算机日常工作中最为重要的事情之一但是今天的计算机更多的时间需要处理的数据可能都是以文本的方式存在的如果我们希望通过Python程序操作本这些文本信息就必须要先了解字符串类型以及与它相关的知识。
第二次世界大战促使了现代电子计算机的诞生,最初计算机被应用于导弹弹道的计算而在计算机诞生后的很多年时间里计算机处理的信息基本上都是数值型的信息。世界上的第一台电子计算机叫ENIAC电子数值积分计算机诞生于美国的宾夕法尼亚大学每秒钟能够完成约5000次浮点运算。随着时间的推移虽然数值运算仍然是计算机日常工作中最为重要的事情之一但是今天的计算机处理得更多的数据可能都是以文本的方式存在的如果我们希望通过Python程序操作本这些文本信息就必须要先了解字符串类型以及与它相关的知识。
所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为![$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](./res/formula_5.png)。
我们可以通过下面的代码来了解字符串的使用。
所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为![$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](./res/formula_5.png)。在Python程序中如果我们把单个或多个字符用单引号或者双引号包围起来就可以表示一个字符串。
```Python
def main():
str1 = 'hello, world!'
# 通过len函数计算字符串的长度
print(len(str1)) # 13
# 获得字符串首字母大写的拷贝
print(str1.capitalize()) # Hello, world!
# 获得字符串变大写后的拷贝
print(str1.upper()) # HELLO, WORLD!
# 从字符串中查找子串所在位置
print(str1.find('or')) # 8
print(str1.find('shit')) # -1
# 与find类似但找不到子串时会引发异常
# print(str1.index('or'))
# print(str1.index('shit'))
# 检查字符串是否以指定的字符串开头
print(str1.startswith('He')) # False
print(str1.startswith('hel')) # True
# 检查字符串是否以指定的字符串结尾
print(str1.endswith('!')) # True
# 将字符串以指定的宽度居中并在两侧填充指定的字符
print(str1.center(50, '*'))
# 将字符串以指定的宽度靠右放置左侧填充指定的字符
print(str1.rjust(50, ' '))
str2 = 'abc123456'
# 从字符串中取出指定位置的字符(下标运算)
print(str2[2]) # c
# 字符串切片(从指定的开始索引到指定的结束索引)
print(str2[2:5]) # c12
print(str2[2:]) # c123456
print(str2[2::2]) # c246
print(str2[::2]) # ac246
print(str2[::-1]) # 654321cba
print(str2[-3:-1]) # 45
# 检查字符串是否由数字构成
print(str2.isdigit()) # False
# 检查字符串是否以字母构成
print(str2.isalpha()) # False
# 检查字符串是否以数字和字母构成
print(str2.isalnum()) # True
str3 = ' jackfrued@126.com '
print(str3)
# 获得字符串修剪左右两侧空格的拷贝
print(str3.strip())
s1 = 'hello, world!'
s2 = "hello, world!"
# 以三个双引号或单引号开头的字符串可以折行
s3 = """
hello,
world!
"""
print(s1, s2, s3, end='')
```
可以在字符串中使用`\`(反斜杠)来表示转义,也就是说`\`后面的字符不再是它原来的意义,例如:`\n`不是代表反斜杠和字符n而是表示换行而`\t`也不是代表反斜杠和字符t而是表示制表符。所以如果想在字符串中表示`'`要写成`\'`,同理想表示`\`要写成`\\`。可以运行下面的代码看看会输出什么。
if __name__ == '__main__':
main()
```Python
s1 = '\'hello, world!\''
s2 = '\n\\hello, world!\\\n'
print(s1, s2, end='')
```
在`\`后面还可以跟一个八进制或者十六进制数来表示字符,例如`\141`和`\x61`都代表小写字母`a`,前者是八进制的表示法,后者是十六进制的表示法。也可以在`\`后面跟Unicode字符编码来表示字符例如`\u9a86\u660a`代表的是中文“骆昊”。运行下面的代码,看看输出了什么。
```Python
s1 = '\141\142\143\x61\x62\x63'
s2 = '\u9a86\u660a'
print(s1, s2)
```
如果不希望字符串中的`\`表示转义,我们可以通过在字符串的最前面加上字母`r`来加以说明,再看看下面的代码又会输出什么。
```Python
s1 = r'\'hello, world!\''
s2 = r'\n\\hello, world!\\\n'
print(s1, s2, end='')
```
Python为字符串类型提供了非常丰富的运算符我们可以使用`+`运算符来实现字符串的拼接,可以使用`*`运算符来重复一个字符串的内容,可以使用`in`和`not in`来判断一个字符串是否包含另外一个字符串(成员运算),我们也可以用`[]`和`[:]`运算符从字符串取出某个字符或某些字符(切片运算),代码如下所示。
```Python
s1 = 'hello ' * 3
print(s1) # hello hello hello
s2 = 'world'
s1 += s2
print(s1) # hello hello hello world
print('ll' in s1) # True
print('good' in s1) # False
str2 = 'abc123456'
# 从字符串中取出指定位置的字符(下标运算)
print(str2[2]) # c
# 字符串切片(从指定的开始索引到指定的结束索引)
print(str2[2:5]) # c12
print(str2[2:]) # c123456
print(str2[2::2]) # c246
print(str2[::2]) # ac246
print(str2[::-1]) # 654321cba
print(str2[-3:-1]) # 45
```
在Python中我们还可以通过一系列的方法来完成对字符串的处理代码如下所示。
```Python
str1 = 'hello, world!'
# 通过内置函数len计算字符串的长度
print(len(str1)) # 13
# 获得字符串首字母大写的拷贝
print(str1.capitalize()) # Hello, world!
# 获得字符串每个单词首字母大写的拷贝
print(str1.title()) # Hello, World!
# 获得字符串变大写后的拷贝
print(str1.upper()) # HELLO, WORLD!
# 从字符串中查找子串所在位置
print(str1.find('or')) # 8
print(str1.find('shit')) # -1
# 与find类似但找不到子串时会引发异常
# print(str1.index('or'))
# print(str1.index('shit'))
# 检查字符串是否以指定的字符串开头
print(str1.startswith('He')) # False
print(str1.startswith('hel')) # True
# 检查字符串是否以指定的字符串结尾
print(str1.endswith('!')) # True
# 将字符串以指定的宽度居中并在两侧填充指定的字符
print(str1.center(50, '*'))
# 将字符串以指定的宽度靠右放置左侧填充指定的字符
print(str1.rjust(50, ' '))
str2 = 'abc123456'
# 检查字符串是否由数字构成
print(str2.isdigit()) # False
# 检查字符串是否以字母构成
print(str2.isalpha()) # False
# 检查字符串是否以数字和字母构成
print(str2.isalnum()) # True
str3 = ' jackfrued@126.com '
print(str3)
# 获得字符串修剪左右两侧空格之后的拷贝
print(str3.strip())
```
我们之前讲过,可以用下面的方式来格式化输出字符串。
```Python
a, b = 5, 10
print('%d * %d = %d' % (a, b, a * b))
```
当然,我们也可以用字符串提供的方法来完成字符串的格式,代码如下所示。
```Python
a, b = 5, 10
print('{0} * {1} = {2}'.format(a, b, a * b))
```
Python 3.6以后,格式化字符串还有更为简洁的书写方式,就是在字符串前加上字母`f`,我们可以使用下面的语法糖来简化上面的代码。
```Python
a, b = 5, 10
print(f'{a} * {b} = {a * b}')
```
除了字符串Python还内置了多种类型的数据结构如果要在程序中保存和操作数据绝大多数时候可以利用现有的数据结构来实现最常用的包括列表、元组、集合和字典。
### 使用列表
下面的代码演示了如何定义列表、使用下标访问列表元素以及添加和删除元素的操作。
不知道大家是否注意到,刚才我们讲到的字符串类型(`str`)和之前我们讲到的数值类型(`int`和`float`)有一些区别。数值类型是标量类型,也就是说这种类型的对象没有可以访问的内部结构;而字符串类型是一种结构化的、非标量类型,所以才会有一系列的属性和方法。接下来我们要介绍的列表(`list`),也是一种结构化的、非标量类型,它是值的有序序列,每个值都可以通过索引进行标识,定义列表可以将列表的元素放在`[]`中,多个元素用`,`进行分隔,可以使用`for`循环对列表元素进行遍历,也可以使用`[]`或`[:]`运算符取出列表中的一个或多个元素。
下面的代码演示了如何定义列表、如何遍历列表以及列表的下标运算。
```Python
def main():
list1 = [1, 3, 5, 7, 100]
print(list1)
list2 = ['hello'] * 5
print(list2)
# 计算列表长度(元素个数)
print(len(list1))
# 下标(索引)运算
print(list1[0])
print(list1[4])
# print(list1[5]) # IndexError: list index out of range
print(list1[-1])
print(list1[-3])
list1[2] = 300
print(list1)
# 添加元素
list1.append(200)
list1.insert(1, 400)
list1 += [1000, 2000]
print(list1)
print(len(list1))
# 删除元素
list1.remove(3)
if 1234 in list1:
list1.remove(1234)
del list1[0]
print(list1)
# 清空列表元素
list1.clear()
print(list1)
list1 = [1, 3, 5, 7, 100]
print(list1) # [1, 3, 5, 7, 100]
# 乘号表示列表元素的重复
list2 = ['hello'] * 3
print(list2) # ['hello', 'hello', 'hello']
# 计算列表长度(元素个数)
print(len(list1)) # 5
# 下标(索引)运算
print(list1[0]) # 1
print(list1[4]) # 100
# print(list1[5]) # IndexError: list index out of range
print(list1[-1]) # 100
print(list1[-3]) # 5
list1[2] = 300
print(list1) # [1, 3, 300, 7, 100]
# 通过循环用下标遍历列表元素
for index in range(len(list1)):
print(list1[index])
# 通过for循环遍历列表元素
for elem in list1:
print(elem)
# 通过enumerate函数处理列表之后再遍历可以同时获得元素索引和值
for index, elem in enumerate(list1):
print(index, elem)
```
下面的代码演示了如何向列表中添加元素以及如何从列表中移除元素。
if __name__ == '__main__':
main()
```Python
list1 = [1, 3, 5, 7, 100]
# 添加元素
list1.append(200)
list1.insert(1, 400)
# 合并两个列表
# list1.extend([1000, 2000])
list1 += [1000, 2000]
print(list1) # [1, 400, 3, 5, 7, 100, 200, 1000, 2000]
print(len(list1)) # 9
# 先通过成员运算判断元素是否在列表中,如果存在就删除该元素
if 3 in list1:
list1.remove(3)
if 1234 in list1:
list1.remove(1234)
print(list1) # [1, 400, 5, 7, 100, 200, 1000, 2000]
# 从指定的位置删除元素
list1.pop(0)
list1.pop(len(list1) - 1)
print(list1) # [400, 5, 7, 100, 200, 1000]
# 清空列表元素
list1.clear()
print(list1) # []
```
和字符串一样,列表也可以做切片操作,通过切片操作我们可以实现对列表的复制或者将列表中的一部分取出来创建出新的列表,代码如下所示。
```Python
def main():
fruits = ['grape', 'apple', 'strawberry', 'waxberry']
fruits += ['pitaya', 'pear', 'mango']
# 循环遍历列表元素
for fruit in fruits:
print(fruit.title(), end=' ')
print()
# 列表切片
fruits2 = fruits[1:4]
print(fruits2)
# fruit3 = fruits # 没有复制列表只创建了新的引用
# 可以通过完整切片操作来复制列表
fruits3 = fruits[:]
print(fruits3)
fruits4 = fruits[-3:-1]
print(fruits4)
# 可以通过反向切片操作来获得倒转后的列表的拷贝
fruits5 = fruits[::-1]
print(fruits5)
if __name__ == '__main__':
main()
fruits = ['grape', 'apple', 'strawberry', 'waxberry']
fruits += ['pitaya', 'pear', 'mango']
# 列表切片
fruits2 = fruits[1:4]
print(fruits2) # apple strawberry waxberry
# 可以通过完整切片操作来复制列表
fruits3 = fruits[:]
print(fruits3) # ['grape', 'apple', 'strawberry', 'waxberry', 'pitaya', 'pear', 'mango']
fruits4 = fruits[-3:-1]
print(fruits4) # ['pitaya', 'pear']
# 可以通过反向切片操作来获得倒转后的列表的拷贝
fruits5 = fruits[::-1]
print(fruits5) # ['mango', 'pear', 'pitaya', 'waxberry', 'strawberry', 'apple', 'grape']
```
下面的代码实现了对列表的排序操作。
```Python
def main():
list1 = ['orange', 'apple', 'zoo', 'internationalization', 'blueberry']
list2 = sorted(list1)
# sorted函数返回列表排序后的拷贝不会修改传入的列表
# 函数的设计就应该像sorted函数一样尽可能不产生副作用
list3 = sorted(list1, reverse=True)
# 通过key关键字参数指定根据字符串长度进行排序而不是默认的字母表顺序
list4 = sorted(list1, key=len)
print(list1)
print(list2)
print(list3)
print(list4)
# 给列表对象发出排序消息直接在列表对象上进行排序
list1.sort(reverse=True)
print(list1)
if __name__ == '__main__':
main()
list1 = ['orange', 'apple', 'zoo', 'internationalization', 'blueberry']
list2 = sorted(list1)
# sorted函数返回列表排序后的拷贝不会修改传入的列表
# 函数的设计就应该像sorted函数一样尽可能不产生副作用
list3 = sorted(list1, reverse=True)
# 通过key关键字参数指定根据字符串长度进行排序而不是默认的字母表顺序
list4 = sorted(list1, key=len)
print(list1)
print(list2)
print(list3)
print(list4)
# 给列表对象发出排序消息直接在列表对象上进行排序
list1.sort(reverse=True)
print(list1)
```
### 生成式和生成器
我们还可以使用列表的生成式语法来创建列表,代码如下所示。
```Python
import sys
def main():
f = [x for x in range(1, 10)]
print(f)
f = [x + y for x in 'ABCDE' for y in '1234567']
print(f)
# 用列表的生成表达式语法创建列表容器
# 用这种语法创建列表之后元素已经准备就绪所以需要耗费较多的内存空间
f = [x ** 2 for x in range(1, 1000)]
print(sys.getsizeof(f)) # 查看对象占用内存的字节数
print(f)
# 请注意下面的代码创建的不是一个列表而是一个生成器对象
# 通过生成器可以获取到数据但它不占用额外的空间存储数据
# 每次需要数据的时候就通过内部的运算得到数据(需要花费额外的时间)
f = (x ** 2 for x in range(1, 1000))
print(sys.getsizeof(f)) # 相比生成式生成器不占用存储数据的空间
print(f)
for val in f:
print(val)
if __name__ == '__main__':
main()
f = [x for x in range(1, 10)]
print(f)
f = [x + y for x in 'ABCDE' for y in '1234567']
print(f)
# 用列表的生成表达式语法创建列表容器
# 用这种语法创建列表之后元素已经准备就绪所以需要耗费较多的内存空间
f = [x ** 2 for x in range(1, 1000)]
print(sys.getsizeof(f)) # 查看对象占用内存的字节数
print(f)
# 请注意下面的代码创建的不是一个列表而是一个生成器对象
# 通过生成器可以获取到数据但它不占用额外的空间存储数据
# 每次需要数据的时候就通过内部的运算得到数据(需要花费额外的时间)
f = (x ** 2 for x in range(1, 1000))
print(sys.getsizeof(f)) # 相比生成式生成器不占用存储数据的空间
print(f)
for val in f:
print(val)
```
除了上面提到的生成器语法Python中还有另外一种定义生成器的方式就是通过`yield`关键字将一个普通函数改造成生成器函数。下面的代码演示了如何实现一个生成[斐波拉切数列](https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97)的生成器。所谓斐波拉切数列可以通过下面[递归](https://zh.wikipedia.org/wiki/%E9%80%92%E5%BD%92)的方法来进行定义:
@ -212,39 +276,34 @@ if __name__ == '__main__':
### 使用元组
Python 的元组与列表类似,不同之处在于元组的元素不能修改,在前面的代码中我们已经不止一次使用过元组了。顾名思义,我们把多个元素组合到一起就形成了一个元组,所以它和列表一样可以保存多条数据。下面的代码演示了如何定义和使用元组。
Python中的元组与列表类似也是一种容器数据类型,可以用一个变量(对象)来存储多个数据,不同之处在于元组的元素不能修改,在前面的代码中我们已经不止一次使用过元组了。顾名思义,我们把多个元素组合到一起就形成了一个元组,所以它和列表一样可以保存多条数据。下面的代码演示了如何定义和使用元组。
```Python
def main():
# 定义元组
t = ('骆昊', 38, True, '四川成都')
print(t)
# 获取元组中的元素
print(t[0])
print(t[3])
# 遍历元组中的值
for member in t:
print(member)
# 重新给元组赋值
# t[0] = '王大锤' # TypeError
# 变量t重新引用了新的元组原来的元组将被垃圾回收
t = ('王大锤', 20, True, '云南昆明')
print(t)
# 将元组转换成列表
person = list(t)
print(person)
# 列表是可以修改它的元素的
person[0] = '李小龙'
person[1] = 25
print(person)
# 将列表转换成元组
fruits_list = ['apple', 'banana', 'orange']
fruits_tuple = tuple(fruits_list)
print(fruits_tuple)
if __name__ == '__main__':
main()
# 定义元组
t = ('骆昊', 38, True, '四川成都')
print(t)
# 获取元组中的元素
print(t[0])
print(t[3])
# 遍历元组中的值
for member in t:
print(member)
# 重新给元组赋值
# t[0] = '王大锤' # TypeError
# 变量t重新引用了新的元组原来的元组将被垃圾回收
t = ('王大锤', 20, True, '云南昆明')
print(t)
# 将元组转换成列表
person = list(t)
print(person)
# 列表是可以修改它的元素的
person[0] = '李小龙'
person[1] = 25
print(person)
# 将列表转换成元组
fruits_list = ['apple', 'banana', 'orange']
fruits_tuple = tuple(fruits_list)
print(fruits_tuple)
```
这里有一个非常值得探讨的问题,我们已经有了列表这种数据结构,为什么还需要元组这样的类型呢?
@ -260,96 +319,106 @@ Python中的集合跟数学上的集合是一致的不允许有重复元素
![](./res/python-set.png)
可以按照下面代码所示的方式来创建和使用集合。
```Python
def main():
set1 = {1, 2, 3, 3, 3, 2}
print(set1)
print('Length =', len(set1))
set2 = set(range(1, 10))
print(set2)
set1.add(4)
set1.add(5)
set2.update([11, 12])
print(set1)
print(set2)
set2.discard(5)
# remove的元素如果不存在会引发KeyError
if 4 in set2:
set2.remove(4)
print(set2)
# 遍历集合容器
for elem in set2:
print(elem ** 2, end=' ')
print()
# 将元组转换成集合
set3 = set((1, 2, 3, 3, 2, 1))
print(set3.pop())
print(set3)
# 集合的交集、并集、差集、对称差运算
print(set1 & set2)
# print(set1.intersection(set2))
print(set1 | set2)
# print(set1.union(set2))
print(set1 - set2)
# print(set1.difference(set2))
print(set1 ^ set2)
# print(set1.symmetric_difference(set2))
# 判断子集和超集
print(set2 <= set1)
# print(set2.issubset(set1))
print(set3 <= set1)
# print(set3.issubset(set1))
print(set1 >= set2)
# print(set1.issuperset(set2))
print(set1 >= set3)
# print(set1.issuperset(set3))
# 创建集合的字面量语法
set1 = {1, 2, 3, 3, 3, 2}
print(set1)
print('Length =', len(set1))
# 创建集合的构造器语法(面向对象部分会进行详细讲解)
set2 = set(range(1, 10))
set3 = set((1, 2, 3, 3, 2, 1))
print(set2, set3)
# 创建集合的推导式语法(推导式也可以用于推导集合)
set4 = {num for num in range(1, 100) if num % 3 == 0 or num % 5 == 0}
print(set4)
```
向集合添加元素和从集合删除元素。
if __name__ == '__main__':
main()
```Python
set1.add(4)
set1.add(5)
set2.update([11, 12])
set2.discard(5)
if 4 in set2:
set2.remove(4)
print(set1, set2)
print(set3.pop())
print(set3)
```
集合的成员、交集、并集、差集等运算。
```Python
# 集合的交集、并集、差集、对称差运算
print(set1 & set2)
# print(set1.intersection(set2))
print(set1 | set2)
# print(set1.union(set2))
print(set1 - set2)
# print(set1.difference(set2))
print(set1 ^ set2)
# print(set1.symmetric_difference(set2))
# 判断子集和超集
print(set2 <= set1)
# print(set2.issubset(set1))
print(set3 <= set1)
# print(set3.issubset(set1))
print(set1 >= set2)
# print(set1.issuperset(set2))
print(set1 >= set3)
# print(set1.issuperset(set3))
```
> **说明:** Python中允许通过一些特殊的方法来为某种类型或数据结构自定义运算符后面的章节中会讲到上面的代码中我们对集合进行运算的时候可以调用集合对象的方法也可以直接使用对应的运算符例如`&`运算符跟intersection方法的作用就是一样的但是使用运算符让代码更加直观。
### 使用字典
字典是另一种可变容器模型,类似于我们生活中使用的字典,它可以存储任意类型对象,与列表、集合不同的是,字典的每个元素都是由一个键和一个值组成的“键值对”,键和值通过冒号分开。下面的代码演示了如何定义和使用字典。
字典是另一种可变容器模型,Python中的字典跟我们生活中使用的字典是一样一样的,它可以存储任意类型对象,与列表、集合不同的是,字典的每个元素都是由一个键和一个值组成的“键值对”,键和值通过冒号分开。下面的代码演示了如何定义和使用字典。
```Python
def main():
scores = {'骆昊': 95, '白元芳': 78, '狄仁杰': 82}
# 通过键可以获取字典中对应的值
print(scores['骆昊'])
print(scores['狄仁杰'])
# 对字典进行遍历(遍历的其实是键再通过键取对应的值)
for elem in scores:
print('%s\t--->\t%d' % (elem, scores[elem]))
# 更新字典中的元素
scores['白元芳'] = 65
scores['诸葛王朗'] = 71
scores.update(冷面=67, 方启鹤=85)
print(scores)
if '武则天' in scores:
print(scores['武则天'])
print(scores.get('武则天'))
# get方法也是通过键获取对应的值但是可以设置默认值
print(scores.get('武则天', 60))
# 删除字典中的元素
print(scores.popitem())
print(scores.popitem())
print(scores.pop('骆昊', 100))
# 清空字典
scores.clear()
print(scores)
if __name__ == '__main__':
main()
# 创建字典的字面量语法
scores = {'骆昊': 95, '白元芳': 78, '狄仁杰': 82}
print(scores)
# 创建字典的构造器语法
items1 = dict(one=1, two=2, three=3, four=4)
# 通过zip函数将两个序列压成字典
items2 = dict(zip(['a', 'b', 'c'], '123'))
# 创建字典的推导式语法
items3 = {num: num ** 2 for num in range(1, 10)}
print(items1, items2, items3)
# 通过键可以获取字典中对应的值
print(scores['骆昊'])
print(scores['狄仁杰'])
# 对字典中所有键值对进行遍历
for key in scores:
print(f'{key}: {scores[key]}')
# 更新字典中的元素
scores['白元芳'] = 65
scores['诸葛王朗'] = 71
scores.update(冷面=67, 方启鹤=85)
print(scores)
if '武则天' in scores:
print(scores['武则天'])
print(scores.get('武则天'))
# get方法也是通过键获取对应的值但是可以设置默认值
print(scores.get('武则天', 60))
# 删除字典中的元素
print(scores.popitem())
print(scores.popitem())
print(scores.pop('骆昊', 100))
# 清空字典
scores.clear()
print(scores)
```
### 练习
#### 练习1在屏幕上显示跑马灯文字
#### 练习1在屏幕上显示跑马灯文字。
参考答案:
```Python
import os
@ -373,6 +442,8 @@ if __name__ == '__main__':
#### 练习2设计一个函数产生指定长度的验证码验证码由大小写字母和数字构成。
参考答案:
```Python
import random
@ -396,6 +467,8 @@ def generate_code(code_len=4):
#### 练习3设计一个函数返回给定文件名的后缀名。
参考答案:
```Python
def get_suffix(filename, has_dot=False):
"""
@ -415,6 +488,8 @@ def get_suffix(filename, has_dot=False):
#### 练习4设计一个函数返回传入的列表中最大和第二大的元素的值。
参考答案:
```Python
def max2(x):
m1, m2 = (x[0], x[1]) if x[0] > x[1] else (x[1], x[0])
@ -427,7 +502,9 @@ def max2(x):
return m1, m2
```
#### 练习5计算指定的年月日是这一年的第几天
#### 练习5计算指定的年月日是这一年的第几天。
参考答案:
```Python
def is_leap_year(year):
@ -472,6 +549,8 @@ if __name__ == '__main__':
#### 练习6打印[杨辉三角](https://zh.wikipedia.org/wiki/%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%92%E5%BD%A2)。
参考答案:
```Python
def main():
num = int(input('Number of rows: '))
@ -493,7 +572,7 @@ if __name__ == '__main__':
### 综合案例
#### 案例1双色球选号
#### 案例1双色球选号
```Python
from random import randrange, randint, sample
@ -534,7 +613,7 @@ if __name__ == '__main__':
> **说明:** 上面使用random模块的sample函数来实现从列表中选择不重复的n个元素。
#### 综合案例2[约瑟夫环问题](https://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98)
#### 综合案例2[约瑟夫环问题](https://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98)
```Python
"""
@ -564,7 +643,7 @@ if __name__ == '__main__':
```
#### 综合案例3[井字棋](https://zh.wikipedia.org/wiki/%E4%BA%95%E5%AD%97%E6%A3%8B)游戏
#### 综合案例3[井字棋](https://zh.wikipedia.org/wiki/%E4%BA%95%E5%AD%97%E6%A3%8B)游戏
```Python
import os

View File

@ -1,8 +1,8 @@
## 面向对象编程基础
活在当下的程序员应该都听过“面向对象编程”一词,也经常有人问能不能用一句话解释下什么是“面向对象编程”,我们先来看看比较正式的说法。
活在当下的程序员应该都听过&quot;面向对象编程&quot;一词,也经常有人问能不能用一句话解释下什么是&quot;面向对象编程&quot;,我们先来看看比较正式的说法。
把一组数据结构和处理它们的方法组成对象object把相同行为的对象归纳为类class通过类的封装encapsulation隐藏内部细节通过继承inheritance实现类的特化specialization和泛化generalization通过多态polymorphism实现基于对象类型的动态分派。
&quot;把一组数据结构和处理它们的方法组成对象object把相同行为的对象归纳为类class通过类的封装encapsulation隐藏内部细节通过继承inheritance实现类的特化specialization和泛化generalization通过多态polymorphism实现基于对象类型的动态分派。&quot;
这样一说是不是更不明白了。所以我们还是看看更通俗易懂的说法,下面这段内容来自于[知乎](https://www.zhihu.com/)。
@ -10,9 +10,9 @@
> **说明:** 以上的内容来自于网络,不代表作者本人的观点和看法,与作者本人立场无关,相关责任不由作者承担。
之前我们说过“程序是指令的集合”我们在程序中书写的语句在执行时会变成一条或多条指令然后由CPU去执行。当然为了简化程序的设计我们引入了函数的概念把相对独立且经常重复使用的代码放置到函数中在需要使用这些功能的时候只要调用函数即可如果一个函数的功能过于复杂和臃肿我们又可以进一步将函数继续切分为子函数来降低系统的复杂性。但是说了这么多不知道大家是否发现所谓编程就是程序员按照计算机的工作方式控制计算机完成各种任务。但是计算机的工作方式与正常人类的思维模式是不同的如果编程就必须得抛弃人类正常的思维方式去迎合计算机编程的乐趣就少了很多“每个人都应该学习编程”这样的豪言壮语就只能说说而已。当然这些还不是最重要的最重要的是当我们需要开发一个复杂的系统时代码的复杂性会让开发和维护工作都变得举步维艰所以在上世纪60年代末期“[软件危机](https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E5%8D%B1%E6%9C%BA)”、“[软件工程](https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B)”等一系列的概念开始在行业中出现。
之前我们说过&quot;**程序是指令的集合**&quot;我们在程序中书写的语句在执行时会变成一条或多条指令然后由CPU去执行。当然为了简化程序的设计我们引入了函数的概念把相对独立且经常重复使用的代码放置到函数中在需要使用这些功能的时候只要调用函数即可如果一个函数的功能过于复杂和臃肿我们又可以进一步将函数继续切分为子函数来降低系统的复杂性。但是说了这么多不知道大家是否发现所谓编程就是程序员按照计算机的工作方式控制计算机完成各种任务。但是计算机的工作方式与正常人类的思维模式是不同的如果编程就必须得抛弃人类正常的思维方式去迎合计算机编程的乐趣就少了很多&quot;每个人都应该学习编程&quot;这样的豪言壮语就只能说说而已。当然这些还不是最重要的最重要的是当我们需要开发一个复杂的系统时代码的复杂性会让开发和维护工作都变得举步维艰所以在上世纪60年代末期&quot;[软件危机](https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E5%8D%B1%E6%9C%BA)&quot;&quot;[软件工程](https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B)&quot;等一系列的概念开始在行业中出现。
当然,程序员圈子内的人都知道,现实中并没有解决上面所说的这些问题的“[银弹](https://zh.wikipedia.org/wiki/%E6%B2%A1%E6%9C%89%E9%93%B6%E5%BC%B9)”真正让软件开发者看到希望的是上世纪70年代诞生的[Smalltalk](https://zh.wikipedia.org/wiki/Smalltalk)编程语言中引入的面向对象的编程思想(面向对象编程的雏形可以追溯到更早期的[Simula](https://zh.wikipedia.org/wiki/Simula)语言)。按照这种编程理念,程序中的数据和操作数据的函数是一个逻辑上的整体,我们称之为“对象”,而我们解决问题的方式就是创建出需要的对象并向对象发出各种各样的消息,多个对象的协同工作最终可以让我们构造出复杂的系统来解决现实中的问题。
当然,程序员圈子内的人都知道,现实中并没有解决上面所说的这些问题的&quot;[银弹](https://zh.wikipedia.org/wiki/%E6%B2%A1%E6%9C%89%E9%93%B6%E5%BC%B9)&quot;真正让软件开发者看到希望的是上世纪70年代诞生的[Smalltalk](https://zh.wikipedia.org/wiki/Smalltalk)编程语言中引入的面向对象的编程思想(面向对象编程的雏形可以追溯到更早期的[Simula](https://zh.wikipedia.org/wiki/Simula)语言)。按照这种编程理念,程序中的数据和操作数据的函数是一个逻辑上的整体,我们称之为“对象”,而我们解决问题的方式就是创建出需要的对象并向对象发出各种各样的消息,多个对象的协同工作最终可以让我们构造出复杂的系统来解决现实中的问题。
> **说明:** 当然面向对象也不是解决软件开发中所有问题的最后的“银弹”所以今天的高级程序设计语言几乎都提供了对多种编程范式的支持Python也不例外。
@ -97,7 +97,7 @@ if __name__ == "__main__":
main()
```
但是Python并没有从语法上严格保证私有属性或方法的私密性它只是给私有的属性和方法换了一个名字来妨碍对它们的访问,事实上如果你知道更换名字的规则仍然可以访问到它们,下面的代码就可以验证这一点。之所以这样设定,可以用这样一句名言加以解释,就是“We are all consenting adults here”。因为绝大多数程序员都认为开放比封闭要好,而且程序员要自己为自己的行为负责。
但是Python并没有从语法上严格保证私有属性或方法的私密性它只是给私有的属性和方法换了一个名字来妨碍对它们的访问事实上如果你知道更换名字的规则仍然可以访问到它们下面的代码就可以验证这一点。之所以这样设定可以用这样一句名言加以解释就是&quot;**We are all consenting adults here**&quot;。因为绝大多数程序员都认为开放比封闭要好,而且程序员要自己为自己的行为负责。
```Python
class Test:
@ -124,11 +124,13 @@ if __name__ == "__main__":
### 面向对象的支柱
面向对象有三大支柱:封装、继承和多态。后面两个概念在下一个章节中进行详细的说明,这里我们先说一下什么是封装。我自己对封装的理解是“隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口”。我们在类中定义的方法其实就是把数据和对数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以执行方法中的代码,也就是说我们只需要知道方法的名字和传入的参数(方法的外部视图),而不需要知道方法内部的实现细节(方法的内部视图)。
面向对象有三大支柱:封装、继承和多态。后面两个概念在下一个章节中进行详细的说明,这里我们先说一下什么是封装。我自己对封装的理解是&quot;隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口&quot;。我们在类中定义的方法其实就是把数据和对数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以执行方法中的代码,也就是说我们只需要知道方法的名字和传入的参数(方法的外部视图),而不需要知道方法内部的实现细节(方法的内部视图)。
### 练习
#### 练习1定义一个类描述数字时钟
#### 练习1定义一个类描述数字时钟。
参考答案:
```Python
from time import sleep
@ -180,6 +182,8 @@ if __name__ == '__main__':
#### 练习2定义一个类描述平面上的点并提供移动点和计算到另一个点距离的方法。
参考答案:
```Python
from math import sqrt

View File

@ -331,7 +331,7 @@ if __name__ == '__main__':
### 综合案例
#### 案例1奥特曼打小怪兽
#### 案例1奥特曼打小怪兽
```Python
from abc import ABCMeta, abstractmethod
@ -521,7 +521,7 @@ if __name__ == '__main__':
main()
```
#### 案例2扑克游戏
#### 案例2扑克游戏
```Python
import random
@ -638,7 +638,7 @@ if __name__ == '__main__':
>**说明:** 大家可以自己尝试在上面代码的基础上写一个简单的扑克游戏例如21点(Black Jack),游戏的规则可以自己在网上找一找。
#### 案例3工资结算系统
#### 案例3工资结算系统
```Python
"""

View File

@ -0,0 +1,74 @@
"""
用Python的turtle模块绘制国旗
"""
import turtle
def draw_rectangle(x, y, width, height):
"""绘制矩形"""
turtle.goto(x, y)
turtle.pencolor('red')
turtle.fillcolor('red')
turtle.begin_fill()
for i in range(2):
turtle.forward(width)
turtle.left(90)
turtle.forward(height)
turtle.left(90)
turtle.end_fill()
def draw_star(x, y, radius):
"""绘制五角星"""
turtle.setpos(x, y)
pos1 = turtle.pos()
turtle.circle(-radius, 72)
pos2 = turtle.pos()
turtle.circle(-radius, 72)
pos3 = turtle.pos()
turtle.circle(-radius, 72)
pos4 = turtle.pos()
turtle.circle(-radius, 72)
pos5 = turtle.pos()
turtle.color('yellow', 'yellow')
turtle.begin_fill()
turtle.goto(pos3)
turtle.goto(pos1)
turtle.goto(pos4)
turtle.goto(pos2)
turtle.goto(pos5)
turtle.end_fill()
def main():
"""主程序"""
turtle.speed(12)
turtle.penup()
x, y = -270, -180
# 画国旗主体
width, height = 540, 360
draw_rectangle(x, y, width, height)
# 画大星星
pice = 22
center_x, center_y = x + 5 * pice, y + height - pice * 5
turtle.goto(center_x, center_y)
turtle.left(90)
turtle.forward(pice * 3)
turtle.right(90)
draw_star(turtle.xcor(), turtle.ycor(), pice * 3)
x_poses, y_poses = [10, 12, 12, 10], [2, 4, 7, 9]
# 画小星星
for x_pos, y_pos in zip(x_poses, y_poses):
turtle.goto(x + x_pos * pice, y + height - y_pos * pice)
turtle.left(turtle.towards(center_x, center_y) - turtle.heading())
turtle.forward(pice)
turtle.right(90)
draw_star(turtle.xcor(), turtle.ycor(), pice)
# 隐藏海龟
turtle.ht()
# 显示绘图窗口
turtle.mainloop()
if __name__ == '__main__':
main()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 816 B

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 B

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 798 B

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 KiB

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 KiB

After

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 KiB

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 KiB

After

Width:  |  Height:  |  Size: 397 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1012 KiB

After

Width:  |  Height:  |  Size: 824 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 KiB

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -288,7 +288,7 @@
- `delete`关键字
- 标准对象
- `Number` / `String` / `Boolean` / `Symbol` / `Array` / `Function`
- `Date` / `Error` / `Math` / `RegEx` / `Object` / `Map` / `Set`
- `Date` / `Error` / `Math` / `RegExp` / `Object` / `Map` / `Set`
- `JSON` / `Promise` / `Generator` / `Reflect` / `Proxy`
#### BOM
@ -903,4 +903,4 @@ Bulma是一个基于Flexbox的现代化的CSS框架其初衷就是移动优
3. 可视化
![](./res/bootstrap-layoutit.png)
![](./res/bootstrap-layoutit.png)

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,80 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
.menu {
margin: 20px 50px;
}
.menu li {
list-style: none;
width: 120px;
height: 35px;
line-height: 35px;
color: white;
text-align: center;
border-bottom: 1px solid lightgray;
}
.menu>li {
background-color: #8FBC8F;
overflow: hidden;
}
.menu>li:hover {
height: auto;
}
.menu li ul li {
background-color: lightsteelblue;
}
</style>
</head>
<body>
<ul class="menu">
<li>
Menu 1
<ul>
<li>Menu 1-1</li>
<li>Menu 1-2</li>
<li>Menu 1-3</li>
</ul>
</li>
<li>
Menu 2
<ul>
<li>Menu 2-1</li>
<li>Menu 2-2</li>
</ul>
</li>
<li>
Menu 3
<ul>
<li>Menu 3-1</li>
<li>Menu 3-2</li>
<li>Menu 3-3</li>
<li>Menu 3-4</li>
<li>Menu 3-5</li>
</ul>
</li>
<li>
Menu 4
<ul>
<li>Menu 4-1</li>
<li>Menu 4-2</li>
</ul>
</li>
<li>
Menu 5
<ul>
<li>Menu 5-1</li>
<li>Menu 5-2</li>
<li>Menu 5-3</li>
<li>Menu 5-4</li>
</ul>
</li>
</ul>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
.menu {
margin: 20px 50px;
}
.menu li {
list-style: none;
width: 120px;
height: 35px;
line-height: 35px;
color: white;
text-align: center;
border-bottom: 1px solid lightgray;
}
.menu>li {
background-color: #8FBC8F;
overflow: hidden;
}
.menu>li:hover {
height: auto;
}
.menu li ul li {
background-color: lightsteelblue;
}
</style>
</head>
<body>
<ul class="menu">
<li>
Menu 1
<ul>
<li>Menu 1-1</li>
<li>Menu 1-2</li>
<li>Menu 1-3</li>
</ul>
</li>
<li>
Menu 2
<ul>
<li>Menu 2-1</li>
<li>Menu 2-2</li>
</ul>
</li>
<li>
Menu 3
<ul>
<li>Menu 3-1</li>
<li>Menu 3-2</li>
<li>Menu 3-3</li>
<li>Menu 3-4</li>
<li>Menu 3-5</li>
</ul>
</li>
<li>
Menu 4
<ul>
<li>Menu 4-1</li>
<li>Menu 4-2</li>
</ul>
</li>
<li>
Menu 5
<ul>
<li>Menu 5-1</li>
<li>Menu 5-2</li>
<li>Menu 5-3</li>
<li>Menu 5-4</li>
</ul>
</li>
</ul>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 KiB

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 KiB

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 794 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 632 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -111,7 +111,7 @@ Linux系统的命令通常都是如下所示的格式
Shell也被称为“壳”或“壳程序”它是用户与操作系统内核交流的翻译官简单的说就是人与计算机交互的界面和接口。目前很多Linux系统默认的Shell都是bash<u>B</u>ourne <u>A</u>gain <u>SH</u>ell因为它可以使用tab键进行命令和路径补全、可以保存历史命令、可以方便的配置环境变量以及执行批处理操作。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# ps
[root ~]# ps
PID TTY TIME CMD
3531 pts/0 00:00:00 bash
3553 pts/0 00:00:00 ps
@ -1283,7 +1283,7 @@ build environment:
### 计划任务
1. 在指定的时间执行命令
1. 在指定的时间执行命令
- **at** - 将任务排队,在指定的时间执行。
- **atq** - 查看待执行的任务队列。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 KiB

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 KiB

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 195 KiB

Some files were not shown because too many files have changed in this diff Show More