commit
dd3ddfa813
|
@ -3,3 +3,14 @@ venv
|
|||
*.pyc
|
||||
__pycache__
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
.vscode/**
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
## Day01 - 初识Python
|
||||
## 初识Python
|
||||
|
||||
### Python简介
|
||||
|
||||
#### 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语言实现的(后面又出现了Java和C#实现的版本Jython和IronPython,以及PyPy、Brython、Pyston等其他实现),可以调用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表示大版本号,一般当整体重写,或出现不向后兼容的改变时,增加A;B表示功能更新,出现新功能时增加B;C表示小的改动(如修复了某个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表示大版本号,一般当整体重写,或出现不向后兼容的改变时,增加A;B表示功能更新,出现新功能时增加B;C表示小的改动(例如:修复了某个Bug),只要有修改就增加C。如果对Python的历史感兴趣,可以阅读名为[《Python简史》](http://www.cnblogs.com/vamei/archive/2013/02/06/2892628.html)的博文。
|
||||
|
||||
#### Python的优缺点
|
||||
|
||||
|
@ -27,18 +27,20 @@ Python的优点很多,简单的可以总结为以下几点。
|
|||
Python的缺点主要集中在以下几点。
|
||||
|
||||
1. 执行效率稍低,因此计算密集型任务可以由C/C++编写。
|
||||
2. 代码无法加密,但是现在的公司很多都不是卖软件而是卖服务,这个问题会被淡化。
|
||||
2. 代码无法加密,但是现在很多公司都不销售卖软件而是销售服务,这个问题会被淡化。
|
||||
3. 在开发时可以选择的框架太多(如Web框架就有100多个),有选择的地方就有错误。
|
||||
|
||||
#### Python的应用领域
|
||||
|
||||
目前Python在云基础设施、DevOps、网络爬虫开发、数据分析挖掘、机器学习等领域都有着广泛的应用,因此也产生了Web后端开发、数据接口开发、自动化运维、自动化测试、科学计算和可视化、数据分析、量化交易、机器人开发、图像识别和处理等一系列的职位。
|
||||
目前Python在Web应用开发、云基础设施、DevOps、网络爬虫开发、数据分析挖掘、机器学习等领域都有着广泛的应用,因此也产生了Web后端开发、数据接口开发、自动化运维、自动化测试、科学计算和可视化、数据分析、量化交易、机器人开发、图像识别和处理等一系列的职位。
|
||||
|
||||
### 搭建编程环境
|
||||
|
||||
#### Windows环境
|
||||
|
||||
可以在[Python官方网站](https://www.python.org)下载到Python的Windows安装程序(exe文件),需要注意的是如果在Windows 7环境下安装需要先安装Service Pack 1补丁包(可以通过一些工具软件自动安装系统补丁的功能来安装),安装过程建议勾选“Add Python 3.6 to PATH”(将Python 3.6添加到PATH环境变量)并选择自定义安装,在设置“Optional Features”界面最好将“pip”、“tcl/tk”、“Python test suite”等项全部勾选上。强烈建议使用自定义的安装路径并保证路径中没有中文。安装完成会看到“Setup was successful”的提示,但是在启动Python环境时可能会因为缺失一些动态链接库文件而导致Python解释器无法运行,常见的问题主要是api-ms-win-crt\*.dll缺失以及更新DirectX之后导致某些动态链接库文件缺失,前者可以参照[《api-ms-win-crt\*.dll缺失原因分析和解决方法》]()一文讲解的方法进行处理或者直接在[微软官网](https://www.microsoft.com/zh-cn/download/details.aspx?id=48145)下载Visual C++ Redistributable for Visual Studio 2015文件进行修复,后者可以下载一个DirectX修复工具进行修复。
|
||||
可以在[Python官方网站](https://www.python.org)下载到Python的Windows安装程序(exe文件),需要注意的是如果在Windows 7环境下安装Python 3.x,需要先安装Service Pack 1补丁包(可以通过一些工具软件自动安装系统补丁的功能来安装),安装过程建议勾选“Add Python 3.x to PATH”(将Python 3.x添加到PATH环境变量)并选择自定义安装,在设置“Optional Features”界面最好将“pip”、“tcl/tk”、“Python test suite”等项全部勾选上。强烈建议选择自定义的安装路径并保证路径中没有中文。安装完成会看到“Setup was successful”的提示。如果稍后运行Python程序时,出现因为缺失一些动态链接库文件而导致Python解释器无法工作的问题,可以按照下面的方法加以解决。
|
||||
|
||||
如果系统显示api-ms-win-crt\*.dll文件缺失,可以参照[《api-ms-win-crt\*.dll缺失原因分析和解决方法》](<https://zhuanlan.zhihu.com/p/32087135>)一文讲解的方法进行处理或者直接在[微软官网](https://www.microsoft.com/zh-cn/download/details.aspx?id=48145)下载Visual C++ Redistributable for Visual Studio 2015文件进行修复;如果是因为更新Windows的DirectX之后导致某些动态链接库文件缺失问题,可以下载一个[DirectX修复工具](<https://dl.pconline.com.cn/download/360074-1.html>)进行修复。
|
||||
|
||||
#### Linux环境
|
||||
|
||||
|
@ -81,24 +83,32 @@ export PATH=$PATH:/usr/local/python37/bin
|
|||
# ... 此处省略下面的代码 ...
|
||||
```
|
||||
|
||||
激活环境变量。
|
||||
|
||||
```Shell
|
||||
source .bash_profile
|
||||
```
|
||||
|
||||
#### MacOS环境
|
||||
#### macOS环境
|
||||
|
||||
MacOS也是自带了Python 2.x版本的,可以通过[Python的官方网站](https://www.python.org)提供的安装文件(pkg文件)安装3.x的版本。默认安装完成后,可以通过在终端执行python命令来启动2.x版本的Python解释器,可以通过执行python3命令来启动3.x版本的Python解释器。
|
||||
macOS也自带了Python 2.x版本,可以通过[Python的官方网站](https://www.python.org)提供的安装文件(pkg文件)安装Python 3.x的版本。默认安装完成后,可以通过在终端执行python命令来启动2.x版本的Python解释器,可以通过执行python3命令来启动3.x版本的Python解释器。
|
||||
|
||||
### 从终端运行Python程序
|
||||
|
||||
#### 确认Python的版本
|
||||
|
||||
在终端或命令行提示符中键入下面的命令。
|
||||
可以Windows的命令行提示符中键入下面的命令。
|
||||
|
||||
```Shell
|
||||
python --version
|
||||
```
|
||||
当然也可以先输入python进入交互式环境,再执行以下的代码检查Python的版本。
|
||||
或者是在Linux或macOS系统的终端中键入下面的命令。
|
||||
|
||||
```Shell
|
||||
python3 --version
|
||||
```
|
||||
|
||||
当然也可以先输入python或python3进入交互式环境,再执行以下的代码检查Python的版本。
|
||||
|
||||
```Python
|
||||
import sys
|
||||
|
@ -109,7 +119,7 @@ print(sys.version)
|
|||
|
||||
#### 编写Python源代码
|
||||
|
||||
可以用文本编辑工具(推荐使用Sublime、Atom、TextMate、VSCode等高级文本编辑工具)编写Python源代码并将其命名为hello.py保存起来,代码内容如下所示。
|
||||
可以用文本编辑工具(推荐使用[Sublime](<https://www.sublimetext.com/>)、[Atom](<https://atom.io/>)、[Visual Studio Code](<https://code.visualstudio.com/>)等高级文本编辑工具)编写Python源代码并用py作为后缀名保存该文件,代码内容如下所示。
|
||||
|
||||
```Python
|
||||
print('hello, world!')
|
||||
|
@ -123,6 +133,12 @@ print('hello, world!')
|
|||
python hello.py
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```Shell
|
||||
python3 hello.py
|
||||
```
|
||||
|
||||
### 代码中的注释
|
||||
|
||||
注释是编程语言的一个重要组成部分,用于在源代码中解释代码的作用从而增强程序的可读性和可维护性,当然也可以将源代码中不需要参与运行的代码段通过注释来去掉,这一点在调试程序的时候经常用到。注释在随源代码进入预处理器或编译时会被移除,不会在目标代码中保留也不会影响程序的执行结果。
|
||||
|
@ -156,56 +172,67 @@ IDLE是安装Python环境时自带的集成开发工具,如下图所示。但
|
|||
|
||||
#### IPython - 更好的交互式编程工具
|
||||
|
||||
IPython是一种基于Python的交互式解释器。相较于原生的Python Shell,IPython提供了更为强大的编辑和交互功能。可以通过Python的包管理工具pip安装IPython和Jupyter,具体的操作如下所示。
|
||||
IPython是一种基于Python的交互式解释器。相较于原生的Python交互式环境,IPython提供了更为强大的编辑和交互功能。可以通过Python的包管理工具pip安装IPython和Jupyter,具体的操作如下所示。
|
||||
|
||||
```Shell
|
||||
pip install ipython jupyter
|
||||
pip install ipython
|
||||
```
|
||||
|
||||
或者
|
||||
或
|
||||
|
||||
```Shell
|
||||
python -m pip install ipython jupyter
|
||||
pip3 install ipython
|
||||
```
|
||||
|
||||
安装成功后,可以通过下面的ipython命令启动IPython,如下图所示。
|
||||
|
||||
![](./res/python-ipython.png)
|
||||
|
||||
当然我们也可以通过Jupyter运行名为notebook的项目在浏览器窗口中进行交互式操作。
|
||||
当然,我们也可以通过安装Jupyter工具并运行名为notebook的程序在浏览器窗口中进行交互式代码编写操作。
|
||||
|
||||
```Shell
|
||||
pip install jupyter
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```Shell
|
||||
pip3 intall jupyter
|
||||
```
|
||||
|
||||
然后执行下面的命令:
|
||||
|
||||
```Shell
|
||||
jupyter notebook
|
||||
```
|
||||
|
||||
|
||||
|
||||
![](./res/python-jupyter-2.png)
|
||||
|
||||
#### anaconda - 一站式的数据科学神器
|
||||
Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。
|
||||
因为包含了大量的科学包,Anaconda 的下载文件比较大(约 531 MB),如果只需要某些包,或者需要节省带宽或存储空间,也可以使用Miniconda这个较小的发行版(仅包含conda和 Python)。
|
||||
对于学习数据科学的人来说,anaconda是绝对的神器,安装简便,而且anaconda支持安装相关软件【例如前文提到的ipython,jupyter notebook,甚至有R等其他数据科学软件 】
|
||||
[一个相当有价值的介绍](https://www.jianshu.com/p/169403f7e40c)
|
||||
现在唯一的问题在于清华镜像服务已经关闭,跨国下载会比较慢
|
||||
|
||||
#### Sublime - 文本编辑神器
|
||||
#### Sublime / Visual Studio Code - 高级文本编辑器
|
||||
|
||||
![](./res/python-sublime.png)
|
||||
|
||||
- 首先可以通过[官方网站](https://www.sublimetext.com/)下载安装程序安装Sublime 3或Sublime 2。
|
||||
|
||||
- 安装包管理工具。通过快捷键Ctrl+`或者在View菜单中选择Show Console打开控制台,输入下面的代码。
|
||||
- 安装包管理工具。
|
||||
1. 通过快捷键Ctrl+`或者在View菜单中选择Show Console打开控制台,输入下面的代码。
|
||||
|
||||
- Sublime 3
|
||||
|
||||
```Python
|
||||
import urllib.request,os;pf='Package Control.sublime-package';ipp=sublime.installed_packages_path();urllib.request.install_opener(urllib.request.build_opener(urllib.request.ProxyHandler()));open(os.path.join(ipp,pf),'wb').write(urllib.request.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read())
|
||||
```
|
||||
|
||||
- Sublime 2
|
||||
|
||||
```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两个选项,如果有,则代表安装成功了。
|
||||
|
||||
|
||||
- 安装插件。通过Preference菜单的Package Control或快捷键Ctrl+Shift+P打开命令面板,在面板中输入Install Package就可以找到安装插件的工具,然后再查找需要的插件。我们推荐大家安装以下几个插件:
|
||||
|
||||
|
@ -215,42 +242,29 @@ Anaconda指的是一个开源的Python发行版本,其包含了conda、Python
|
|||
- Python PEP8 Autoformat - PEP8规范自动格式化插件。
|
||||
- ConvertToUTF8 - 将本地编码转换为UTF-8。
|
||||
|
||||
> 说明:事实上Visual Studio Code可能是更好的选择,它不用花钱并提供了更为完整和强大的功能,有兴趣的读者可以自行研究。
|
||||
|
||||
#### PyCharm - Python开发神器
|
||||
|
||||
PyCharm的安装、配置和使用我们在后面会进行介绍。
|
||||
PyCharm的安装、配置和使用在[《玩转PyCharm》](../玩转PyCharm.md)进行了介绍,有兴趣的读者可以选择阅读。
|
||||
|
||||
![](./res/python-pycharm.png)
|
||||
|
||||
### 练习
|
||||
|
||||
1. 在Python交互环境中查看下面的代码结果,并将内容翻译成中文。
|
||||
1. 在Python交互环境中查看下面的代码结果,并试着将这些内容翻译成中文。
|
||||
|
||||
```Python
|
||||
import this
|
||||
|
||||
Beautiful is better than ugly.
|
||||
Explicit is better than implicit.
|
||||
Simple is better than complex.
|
||||
Complex is better than complicated.
|
||||
Flat is better than nested.
|
||||
Sparse is better than dense.
|
||||
Readability counts.
|
||||
Special cases aren't special enough to break the rules.
|
||||
Although practicality beats purity.
|
||||
Errors should never pass silently.
|
||||
Unless explicitly silenced.
|
||||
In the face of ambiguity, refuse the temptation to guess.
|
||||
There should be one-- and preferably only one --obvious way to do it.
|
||||
Although that way may not be obvious at first unless you're Dutch.
|
||||
Now is better than never.
|
||||
Although never is often better than *right* now.
|
||||
If the implementation is hard to explain, it's a bad idea.
|
||||
If the implementation is easy to explain, it may be a good idea.
|
||||
Namespaces are one honking great idea -- let's do more of those!
|
||||
```
|
||||
|
||||
> 说明:当前键入上面的命令后会在交互式环境中看到如下所示的输出,这段内容被称为“Python之禅”,里面讲述的道理不仅仅适用于Python,也适用于其他编程语言。
|
||||
>
|
||||
|
||||
2. 学习使用turtle在屏幕上绘制图形。
|
||||
|
||||
> 说明:turtle是Python内置的一个非常有趣的模块,特别适用于让小朋友体会什么是编程,它最早是Logo语言的一部分,Logo语言是Wally Feurzig和Seymour Papert在1966发明的编程语言.
|
||||
|
||||
```Python
|
||||
import turtle
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
## Day02 - 语言元素
|
||||
## 语言元素
|
||||
|
||||
#### 指令和程序
|
||||
|
||||
计算机的硬件系统通常由五大部件构成,包括:运算器、控制器、存储器、输入设备和输出设备。其中,运算器和控制器放在一起就是我们通常所说的中央处理器,它的功能是执行各种运算和控制指令以及处理计算机软件中的数据。我们通常所说的程序实际上就是指令的集合,我们程序就是将一系列的指令按照某种方式组织到一起,然后通过这些指令去控制计算机做我们想让它做的事情。今天我们使用的计算机虽然器件做工越来越精密,处理能力越来越强大,但究其本质来说仍然属于[“冯·诺依曼结构”](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)科普一下。
|
||||
计算机的硬件系统通常由五大部件构成,包括:运算器、控制器、存储器、输入设备和输出设备。其中,运算器和控制器放在一起就是我们通常所说的中央处理器,它的功能是执行各种运算和控制指令以及处理计算机软件中的数据。我们通常所说的程序实际上就是指令的集合,我们程序就是将一系列的指令按照某种方式组织到一起,然后通过这些指令去控制计算机做我们想让它做的事情。今天我们大多数时候使用的计算机,虽然它们的元器件做工越来越精密,处理能力越来越强大,但究其本质来说仍然属于[“冯·诺依曼结构”](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向全世界发布了首款商业化量子计算机。
|
||||
|
||||
### 变量和类型
|
||||
|
||||
在程序设计中,变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。计算机能处理的数据有很多中类型,除了数值之外还可以处理文本、图形、音频、视频等各种各样的数据,那么不同的数据就需要定义不同的存储类型。Python中的数据类型很多,而且也允许我们自定义新的数据类型(这一点在后面会讲到),我们先介绍几种常用的数据类型。
|
||||
在程序设计中,变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。计算机能处理的数据有很多种类型,除了数值之外还可以处理文本、图形、音频、视频等各种各样的数据,那么不同的数据就需要定义不同的存储类型。Python中的数据类型很多,而且也允许我们自定义新的数据类型(这一点在后面会讲到),我们先介绍几种常用的数据类型。
|
||||
|
||||
- 整型:Python中可以处理任意大小的整数(Python 2.x中有int和long两种类型的整数,但这种区分对Python来说意义不大,因此在Python 3.x中整数只有int这一种了),而且支持二进制(如`0b100`,换算成十进制是4)、八进制(如`0o100`,换算成十进制是64)、十进制(`100`)和十六进制(`0x100`,换算成十进制是256)的表示法。
|
||||
- 浮点型:浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如`123.456`)之外还支持科学计数法(如`1.23456e2`)。
|
||||
|
@ -50,12 +52,11 @@ print(a / b)
|
|||
print(a // b)
|
||||
print(a % b)
|
||||
print(a ** b)
|
||||
|
||||
```
|
||||
|
||||
```Python
|
||||
"""
|
||||
使用input函数输入
|
||||
使用input()函数获取键盘输入
|
||||
使用int()进行类型转换
|
||||
用占位符格式化输出的字符串
|
||||
|
||||
|
@ -72,7 +73,6 @@ print('%d / %d = %f' % (a, b, a / b))
|
|||
print('%d // %d = %d' % (a, b, a // b))
|
||||
print('%d %% %d = %d' % (a, b, a % b))
|
||||
print('%d ** %d = %d' % (a, b, a ** b))
|
||||
|
||||
```
|
||||
|
||||
```Python
|
||||
|
@ -94,16 +94,15 @@ print(type(b))
|
|||
print(type(c))
|
||||
print(type(d))
|
||||
print(type(e))
|
||||
|
||||
```
|
||||
|
||||
在对变量类型进行转换时可以使用Python的内置函数(准确的说下面列出的并不是真正意义上的函数,而是后面我们要讲到的创建对象的构造方法)。
|
||||
|
||||
- int():将一个数值或字符串转换成整数,可以指定进制。
|
||||
- float():将一个字符串转换成浮点数。
|
||||
- str():将指定的对象转换成字符串形式,可以指定编码。
|
||||
- chr():将整数转换成该编码对应的字符串(一个字符)。
|
||||
- ord():将字符串(一个字符)转换成对应的编码(整数)。
|
||||
- `int()`:将一个数值或字符串转换成整数,可以指定进制。
|
||||
- `float()`:将一个字符串转换成浮点数。
|
||||
- `str()`:将指定的对象转换成字符串形式,可以指定编码。
|
||||
- `chr()`:将整数转换成该编码对应的字符串(一个字符)。
|
||||
- `ord()`:将字符串(一个字符)转换成对应的编码(整数)。
|
||||
|
||||
### 运算符
|
||||
|
||||
|
@ -118,7 +117,7 @@ Python支持多种运算符,下表大致按照优先级从高到低的顺序
|
|||
| `+` `-` | 加,减 |
|
||||
| `>>` `<<` | 右移,左移 |
|
||||
| `&` | 按位与 |
|
||||
| `^` `|` | 按位异或,按位或 |
|
||||
| `^` `\|` | 按位异或,按位或 |
|
||||
| `<=` `<` `>` `>=` | 小于等于,小于,大于,大于等于 |
|
||||
| `==` `!=` | 等于,不等于 |
|
||||
| `is` `is not` | 身份运算符 |
|
||||
|
@ -126,7 +125,7 @@ Python支持多种运算符,下表大致按照优先级从高到低的顺序
|
|||
| `not` `or` `and` | 逻辑运算符 |
|
||||
| `=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` `|=` `^=` `>>=` `<<=` | (复合)赋值运算符 |
|
||||
|
||||
>**说明:**在实际开发中,如果搞不清楚优先级可以使用括号来确保运算的执行顺序。
|
||||
>**说明:** 在实际开发中,如果搞不清楚运算符的优先级,可以使用括号来确保运算的执行顺序。
|
||||
|
||||
下面的例子演示了运算符的使用。
|
||||
|
||||
|
@ -161,7 +160,6 @@ print("flag4 = ", flag4)
|
|||
print("flag5 = ", flag5)
|
||||
print(flag1 is True)
|
||||
print(flag2 is not False)
|
||||
|
||||
```
|
||||
|
||||
### 练习
|
||||
|
@ -180,7 +178,6 @@ Author: 骆昊
|
|||
f = float(input('请输入华氏温度: '))
|
||||
c = (f - 32) / 1.8
|
||||
print('%.1f华氏度 = %.1f摄氏度' % (f, c))
|
||||
|
||||
```
|
||||
|
||||
#### 练习2:输入圆的半径计算计算周长和面积。
|
||||
|
@ -200,7 +197,6 @@ perimeter = 2 * math.pi * radius
|
|||
area = math.pi * radius * radius
|
||||
print('周长: %.2f' % perimeter)
|
||||
print('面积: %.2f' % area)
|
||||
|
||||
```
|
||||
|
||||
#### 练习3:输入年份判断是不是闰年。
|
|
@ -1,12 +1,12 @@
|
|||
## Day03 - 分支结构
|
||||
## 分支结构
|
||||
|
||||
### 分支结构的应用场景
|
||||
### 应用场景
|
||||
|
||||
迄今为止,我们写的Python代码都是一条一条语句顺序执行,这种结构的代码我们称之为顺序结构。然而仅有顺序结构并不能解决所有的问题,比如我们设计一个游戏,游戏第一关的通关条件是玩家获得1000分,那么在完成本局游戏后我们要根据玩家得到分数来决定究竟是进入第二关还是告诉玩家“Game Over”,这里就会产生两个分支,而且这两个分支只有一个会被执行,这就是程序中分支结构。类似的场景还有很多,给大家一分钟的时间,你应该可以想到至少5个以上这样的例子,赶紧试一试。
|
||||
迄今为止,我们写的Python代码都是一条一条语句顺序执行,这种代码结构通常称之为顺序结构。然而仅有顺序结构并不能解决所有的问题,比如我们设计一个游戏,游戏第一关的通关条件是玩家获得1000分,那么在完成本局游戏后,我们要根据玩家得到分数来决定究竟是进入第二关,还是告诉玩家“Game Over”,这里就会产生两个分支,而且这两个分支只有一个会被执行。类似的场景还有很多,我们将这种结构称之为“分支结构”或“选择结构”。给大家一分钟的时间,你应该可以想到至少5个以上这样的例子,赶紧试一试。
|
||||
|
||||
### if语句的使用
|
||||
|
||||
在Python中,要构造分支结构可以使用`if`、`elif`和`else`关键字。所谓关键字就是有特殊含义的单词,像`if`和`else`就是专门用于构造分支结构的关键字,很显然你不能够使用它作为变量名(事实上,用作其他的标识符也是不可以)。下面的例子中演示了如何构造一个分支结构。
|
||||
在Python中,要构造分支结构可以使用`if`、`elif`和`else`关键字。所谓**关键字**就是有特殊含义的单词,像`if`和`else`就是专门用于构造分支结构的关键字,很显然你不能够使用它作为变量名(事实上,用作其他的标识符也是不可以)。下面的例子中演示了如何构造一个分支结构。
|
||||
|
||||
```Python
|
||||
"""
|
||||
|
@ -31,7 +31,7 @@ else:
|
|||
|
||||
当然如果要构造出更多的分支,可以使用`if…elif…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}$$
|
||||
![$$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)
|
||||
|
||||
```Python
|
||||
"""
|
||||
|
@ -79,7 +79,7 @@ else:
|
|||
print('f(%.2f) = %.2f' % (x, y))
|
||||
```
|
||||
|
||||
> **说明:**大家可以自己感受一下这两种写法到底是哪一种更好。在之前我们提到的Python之禅中有这么一句话“Flat is better than nested.”,之所以提出这个观点是因为嵌套结构的嵌套层次多了之后会严重的影响代码的可读性,如果可以使用扁平化的结构就不要去用嵌套,因此之前的写法是更好的做法。
|
||||
> **说明:** 大家可以自己感受一下这两种写法到底是哪一种更好。在之前我们提到的Python之禅中有这么一句话“Flat is better than nested.”,之所以提倡代码“扁平化”是因为嵌套结构的嵌套层次多了之后会严重的影响代码的可读性,所以能使用扁平化的结构时就不要使用嵌套。
|
||||
|
||||
### 练习
|
||||
|
||||
|
@ -130,7 +130,7 @@ else:
|
|||
result = '讲冷笑话'
|
||||
print(result)
|
||||
```
|
||||
> **说明:**上面的代码中使用了random模块的randint函数生成指定范围的随机数来模拟掷骰子。
|
||||
> **说明:** 上面的代码中使用了random模块的randint函数生成指定范围的随机数来模拟掷骰子。
|
||||
|
||||
#### 练习3:百分制成绩转等级制
|
||||
|
||||
|
@ -184,7 +184,7 @@ if a + b > c and a + c > b and b + c > a:
|
|||
else:
|
||||
print('不能构成三角形')
|
||||
```
|
||||
> **说明:**上面的代码中使用了`math`模块的`sqrt`函数来计算平方根。用边长计算三角形面积的公式叫做[海伦公式](https://zh.wikipedia.org/zh-hans/海伦公式)。
|
||||
> **说明:** 上面的代码中使用了`math`模块的`sqrt`函数来计算平方根。用边长计算三角形面积的公式叫做[海伦公式](https://zh.wikipedia.org/zh-hans/海伦公式)。
|
||||
|
||||
#### 练习5:个人所得税计算器。
|
||||
|
||||
|
@ -227,4 +227,4 @@ tax = abs(diff * rate - deduction)
|
|||
print('个人所得税: ¥%.2f元' % tax)
|
||||
print('实际到手收入: ¥%.2f元' % (diff + 3500 - tax))
|
||||
```
|
||||
>**说明:**上面的代码中使用了Python内置的`abs()`函数取绝对值来处理`-0`的问题。
|
||||
>**说明:** 上面的代码中使用了Python内置的`abs()`函数取绝对值来处理`-0`的问题。
|
|
@ -1,12 +1,14 @@
|
|||
## Day04 - 循环结构
|
||||
## 循环结构
|
||||
|
||||
### 循环结构的应用场景
|
||||
### 应用场景
|
||||
|
||||
如果在程序中我们需要重复的执行某条或某些指令,例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向奔跑的指令。当然你可能已经注意到了,刚才的描述中其实不仅仅有需要重复的动作,还有我们上一个章节讲到的分支结构。再举一个简单的例子,比如在我们的程序中要实现每隔1秒中在屏幕上打印一个"hello, world"这样的字符串并持续一个小时,我们肯定不能够将`print('hello, world')`这句代码写上3600遍,如果真的需要这样做那么编程的工作就太无聊了。因此,我们需要了解一下循环结构,有了循环结构我们就可以轻松的控制某件事或者某些事重复、重复、再重复的发生。在Python中构造循环结构有两种做法,一种是`for-in`循环,一种是`while`循环。
|
||||
如果在程序中我们需要重复的执行某条或某些指令,例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向奔跑的指令。当然你可能已经注意到了,刚才的描述中其实不仅仅有需要重复的动作,还有我们上一个章节讲到的分支结构。再举一个简单的例子,比如在我们的程序中要实现每隔1秒中在屏幕上打印一个"hello, world"这样的字符串并持续一个小时,我们肯定不能够将`print('hello, world')`这句代码写上3600遍,如果真的需要这样做,那么编程的工作就太无聊了。因此,我们还需要了解一下循环结构,有了循环结构我们就可以轻松的控制某件事或者某些事重复、重复、再重复的去执行。
|
||||
|
||||
在Python中构造循环结构有两种做法,一种是`for-in`循环,一种是`while`循环。
|
||||
|
||||
### for-in循环
|
||||
|
||||
如果明确的知道循环执行的次数或者是要对一个容器进行迭代(后面会讲到),那么我们推荐使用`for-in`循环,例如下面代码中计算$\sum_{n=1}^{100}n$。
|
||||
如果明确的知道循环执行的次数或者要对一个容器进行迭代(后面会讲到),那么我们推荐使用`for-in`循环,例如下面代码中计算1~100求和的结果($\displaystyle \sum \limits_{n=1}^{100}n$)。
|
||||
|
||||
```Python
|
||||
"""
|
||||
|
@ -63,7 +65,7 @@ print(sum)
|
|||
|
||||
### while循环
|
||||
|
||||
如果要构造不知道具体循环次数的循环结构,我们推荐使用`while`循环,`while`循环通过一个能够产生或转换出`bool`值的表达式来控制循环,表达式的值为`True`循环继续,表达式的值为`False`循环结束。下面我们通过一个“猜数字”的小游戏(计算机出一个1~100之间的随机数,人输入自己猜的数字,计算机给出对应的提示信息,直到人猜出计算机出的数字)来看看如何使用`while`循环。
|
||||
如果要构造不知道具体循环次数的循环结构,我们推荐使用`while`循环。`while`循环通过一个能够产生或转换出`bool`值的表达式来控制循环,表达式的值为`True`循环继续,表达式的值为`False`循环结束。下面我们通过一个“猜数字”的小游戏(计算机出一个1~100之间的随机数,人输入自己猜的数字,计算机给出对应的提示信息,直到人猜出计算机出的数字)来看看如何使用`while`循环。
|
||||
|
||||
```Python
|
||||
"""
|
||||
|
@ -94,7 +96,7 @@ if counter > 7:
|
|||
print('你的智商余额明显不足')
|
||||
```
|
||||
|
||||
> **说明:**上面的代码中使用了`break`关键字来提前终止循环,需要注意的是`break`只能终止它所在的那个循环,这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。除了`break`之外,还有另一个关键字是`continue`,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。
|
||||
> **说明:** 上面的代码中使用了`break`关键字来提前终止循环,需要注意的是`break`只能终止它所在的那个循环,这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。除了`break`之外,还有另一个关键字是`continue`,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。
|
||||
|
||||
和分支结构一样,循环结构也是可以嵌套的,也就是说在循环中还可以构造循环结构。下面的例子演示了如何通过嵌套的循环来输出一个九九乘法表。
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
## 构造程序逻辑
|
||||
|
||||
分支和循环结构会帮助我们将程序中逻辑建立起来,将来我们的程序无论简单复杂,都是由顺序结构、分支结构、循环结构构成的。对于编程语言的初学者来说,首先要锻炼的是将人类自然语言描述的解决问题的步骤和方法翻译成代码的能力,其次就是熟练的运用之前学过的运算符、表达式以及最近的两个章节讲解的分支结构和循环结构的知识。有了这些基本的能力才能够通过计算机程序去解决各种各样的现实问题。所以,开始做练习吧!
|
||||
|
||||
### 练习清单
|
||||
|
||||
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目录下。
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
在讲解本章节的内容之前,我们先来研究一道数学题,请说出下面的方程有多少组正整数解。
|
||||
|
||||
$$x_1 + x_2 + x_3 + x_4 = 8$$
|
||||
![$$x_1 + x_2 + x_3 + x_4 = 8$$](./res/formula_3.png)
|
||||
|
||||
事实上,上面的问题等同于将8个苹果分成四组每组至少一个苹果有多少种方案。想到这一点问题的答案就呼之欲出了。
|
||||
|
||||
$$C_M^N =\frac{M!}{N!(M-N)!}, \text{(M=7, N=3)} $$
|
||||
![$$C_M^N =\frac{M!}{N!(M-N)!}, \text{(M=7, N=3)} $$](./res/formula_4.png)
|
||||
|
||||
可以用Python的程序来计算出这个值,代码如下所示。
|
||||
|
||||
|
@ -31,7 +31,7 @@ print(fm // fn // fmn)
|
|||
|
||||
### 函数的作用
|
||||
|
||||
不知道大家是否注意到,在上面的代码中,我们做了3次求阶乘,这样的代码实际上就是重复代码。编程大师Martin Fowler先生曾经说过:“代码有很多种坏味道,重复是最坏的一种!”,要写出高质量的代码首先要解决的就是重复代码的问题。对于上面的代码来说,我们可以将计算阶乘的功能封装到一个称之为“函数”的功能模块中,在需要计算阶乘的地方,我们只需要“调用”这个“函数”就可以了。
|
||||
不知道大家是否注意到,在上面的代码中,我们做了3次求阶乘,这样的代码实际上就是重复代码。编程大师*Martin Fowler*先生曾经说过:“**代码有很多种坏味道,重复是最坏的一种!**”,要写出高质量的代码首先要解决的就是重复代码的问题。对于上面的代码来说,我们可以将计算阶乘的功能封装到一个称之为“函数”的功能模块中,在需要计算阶乘的地方,我们只需要“调用”这个“函数”就可以了。
|
||||
|
||||
### 定义函数
|
||||
|
||||
|
@ -59,7 +59,7 @@ n = int(input('n = '))
|
|||
print(factorial(m) // factorial(n) // factorial(m - n))
|
||||
```
|
||||
|
||||
> **说明:**Python的math模块中其实已经有一个factorial函数了,事实上要计算阶乘可以直接使用这个现成的函数而不用自己定义。下面例子中的某些函数其实Python中也是内置了,我们这里是为了讲解函数的定义和使用才把它们又实现了一遍,实际开发中不建议做这种低级的重复性的工作。
|
||||
> **说明:** Python的math模块中其实已经有一个factorial函数了,事实上要计算阶乘可以直接使用这个现成的函数而不用自己定义。下面例子中的某些函数其实Python中也是内置了,我们这里是为了讲解函数的定义和使用才把它们又实现了一遍,实际开发中不建议做这种低级的重复性的工作。
|
||||
|
||||
|
||||
### 函数的参数
|
||||
|
@ -337,7 +337,7 @@ if __name__ == '__main__':
|
|||
|
||||
在实际开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被[垃圾回收](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代码按照下面的格式进行书写,这一点点的改进其实就是在我们理解了函数和作用域的基础上跨出的巨大的一步。
|
||||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
### 使用字符串
|
||||
|
||||
第二次世界大战促使了现代电子计算机的诞生,当初的想法很简单,就是用计算机来计算导弹的弹道,因此在计算机刚刚诞生的那个年代,计算机处理的信息主要是数值,而世界上的第一台电子计算机ENIAC每秒钟能够完成约5000次浮点运算。随着时间的推移,虽然对数值运算仍然是计算机日常工作中最为重要的事情之一,但是今天的计算机处理得更多的数据都是以文本信息的方式存在的,而Python表示文本信息的方式我们在很早以前就说过了,那就是字符串类型。所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为[$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](https://wikimedia.org/api/rest_v1/media/math/render/svg/e29bf631b090323edd6889f810e6cff29538b161)。
|
||||
第二次世界大战促使了现代电子计算机的诞生,最初的目的用计算机来快速的完成导弹弹道的计算,因此在计算机刚刚诞生的那个年代,计算机处理的信息基本上都是数值型的信息,而世界上的第一台电子计算机ENIAC每秒钟能够完成约5000次浮点运算。随着时间的推移,虽然数值运算仍然是计算机日常工作中最为重要的事情之一,但是今天的计算机更多的时间需要处理的数据可能都是以文本的方式存在的,如果我们希望通过Python程序操作本这些文本信息,就必须要先了解字符串类型以及与它相关的知识。
|
||||
|
||||
所谓**字符串**,就是由零个或多个字符组成的有限序列,一般记为![$${\displaystyle s=a_{1}a_{2}\dots a_{n}(0\leq n \leq \infty)}$$](./res/formula_5.png)。
|
||||
|
||||
我们可以通过下面的代码来了解字符串的使用。
|
||||
|
||||
|
@ -104,8 +106,8 @@ if __name__ == '__main__':
|
|||
```Python
|
||||
def main():
|
||||
fruits = ['grape', 'apple', 'strawberry', 'waxberry']
|
||||
fruits += ['pitaya', 'pear', 'mango']
|
||||
# 循环遍历列表元素
|
||||
fruits += ['pitaya', 'pear', 'mango']
|
||||
# 循环遍历列表元素
|
||||
for fruit in fruits:
|
||||
print(fruit.title(), end=' ')
|
||||
print()
|
||||
|
@ -183,11 +185,11 @@ if __name__ == '__main__':
|
|||
|
||||
除了上面提到的生成器语法,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)的方法来进行定义:
|
||||
|
||||
$${\displaystyle F_{0}=0}$$
|
||||
![$${\displaystyle F_{0}=0}$$](./res/formula_6.png)
|
||||
|
||||
$${\displaystyle F_{1}=1}$$
|
||||
![$${\displaystyle F_{1}=1}$$](./res/formula_7.png)
|
||||
|
||||
$${\displaystyle F_{n}=F_{n-1}+F_{n-2}}({n}\geq{2})$$
|
||||
![$${\displaystyle F_{n}=F_{n-1}+F_{n-2}}({n}\geq{2})$$](./res/formula_8.png)
|
||||
|
||||
![](./res/fibonacci-blocks.png)
|
||||
|
||||
|
@ -307,7 +309,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:Python中允许通过一些特殊的方法来为某种类型或数据结构自定义运算符(后面的章节中会讲到),上面的代码中我们对集合进行运算的时候可以调用集合对象的方法,也可以直接使用对应的运算符,例如`&`运算符跟intersection方法的作用就是一样的,但是使用运算符让代码更加直观。
|
||||
> **说明:** Python中允许通过一些特殊的方法来为某种类型或数据结构自定义运算符(后面的章节中会讲到),上面的代码中我们对集合进行运算的时候可以调用集合对象的方法,也可以直接使用对应的运算符,例如`&`运算符跟intersection方法的作用就是一样的,但是使用运算符让代码更加直观。
|
||||
|
||||
### 使用字典
|
||||
|
||||
|
@ -530,7 +532,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:上面使用random模块的sample函数来实现从列表中选择不重复的n个元素。
|
||||
> **说明:** 上面使用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)
|
||||
|
||||
|
@ -609,4 +611,4 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
>**说明**:最后这个案例来自[《Python编程快速上手:让繁琐工作自动化》](https://item.jd.com/11943853.html)一书(这本书对有编程基础想迅速使用Python将日常工作自动化的人来说还是不错的选择),对代码做了一点点的调整。
|
||||
>**说明:** 最后这个案例来自[《Python编程快速上手:让繁琐工作自动化》](https://item.jd.com/11943853.html)一书(这本书对有编程基础想迅速使用Python将日常工作自动化的人来说还是不错的选择),对代码做了一点点的调整。
|
|
@ -2,19 +2,19 @@
|
|||
|
||||
活在当下的程序员应该都听过“面向对象编程”一词,也经常有人问能不能用一句话解释下什么是“面向对象编程”,我们先来看看比较正式的说法。
|
||||
|
||||
> 把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。
|
||||
“把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。”
|
||||
|
||||
这样一说是不是更不明白了。所以我们还是看看更通俗易懂的说法,下面这段内容来自于[知乎](https://www.zhihu.com/)。
|
||||
|
||||
![](./res/oop-zhihu.png)
|
||||
|
||||
> **说明**:以上的内容来自于网络,不代表作者本人的观点和看法,与作者本人立场无关,相关责任不由作者承担。
|
||||
> **说明:** 以上的内容来自于网络,不代表作者本人的观点和看法,与作者本人立场无关,相关责任不由作者承担。
|
||||
|
||||
之前我们说过“程序是指令的集合”,我们在程序中书写的语句在执行时会变成一条或多条指令然后由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)”等一系列的概念开始在行业中出现。
|
||||
|
||||
当然,程序员圈子内的人都知道,现实中并没有解决上面所说的这些问题的“[银弹](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)语言)。按照这种编程理念,程序中的数据和操作数据的函数是一个逻辑上的整体,我们称之为“对象”,而我们解决问题的方式就是创建出需要的对象并向对象发出各种各样的消息,多个对象的协同工作最终可以让我们构造出复杂的系统来解决现实中的问题。
|
||||
|
||||
> **说明**:当然面向对象也不是解决软件开发中所有问题的最后的“银弹”,所以今天的高级程序设计语言几乎都提供了对多种编程范式的支持,Python也不例外。
|
||||
> **说明:** 当然面向对象也不是解决软件开发中所有问题的最后的“银弹”,所以今天的高级程序设计语言几乎都提供了对多种编程范式的支持,Python也不例外。
|
||||
|
||||
### 类和对象
|
||||
|
||||
|
@ -39,15 +39,15 @@ class Student(object):
|
|||
print('%s正在学习%s.' % (self.name, course_name))
|
||||
|
||||
# PEP 8要求标识符的名字用全小写多个单词用下划线连接
|
||||
# 但是很多程序员和公司更倾向于使用驼峰命名法(驼峰标识)
|
||||
def watch_av(self):
|
||||
# 但是部分程序员和公司更倾向于使用驼峰命名法(驼峰标识)
|
||||
def watch_movie(self):
|
||||
if self.age < 18:
|
||||
print('%s只能观看《熊出没》.' % self.name)
|
||||
else:
|
||||
print('%s正在观看岛国爱情动作片.' % self.name
|
||||
print('%s正在观看岛国爱情大电影.' % self.name)
|
||||
```
|
||||
|
||||
> **说明**:写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息。
|
||||
> **说明:** 写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息。
|
||||
|
||||
### 创建和使用对象
|
||||
|
||||
|
@ -60,10 +60,10 @@ def main():
|
|||
# 给对象发study消息
|
||||
stu1.study('Python程序设计')
|
||||
# 给对象发watch_av消息
|
||||
stu1.watch_av()
|
||||
stu1.watch_movie()
|
||||
stu2 = Student('王大锤', 15)
|
||||
stu2.study('思想品德')
|
||||
stu2.watch_av()
|
||||
stu2.watch_movie()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -131,6 +131,9 @@ if __name__ == "__main__":
|
|||
#### 练习1:定义一个类描述数字时钟
|
||||
|
||||
```Python
|
||||
from time import sleep
|
||||
|
||||
|
||||
class Clock(object):
|
||||
"""数字时钟"""
|
||||
|
||||
|
@ -237,4 +240,4 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:本章中的插图来自于Grady Booch等著作的[《面向对象分析与设计》](https://item.jd.com/20476561918.html)一书,该书是讲解面向对象编程的经典著作,有兴趣的读者可以购买和阅读这本书来了解更多的面向对象的相关知识。
|
||||
> **说明:** 本章中的插图来自于Grady Booch等著作的[《面向对象分析与设计》](https://item.jd.com/20476561918.html)一书,该书是讲解面向对象编程的经典著作,有兴趣的读者可以购买和阅读这本书来了解更多的面向对象的相关知识。
|
|
@ -276,7 +276,7 @@ def main():
|
|||
stu = Student('王大锤', 15, '初三')
|
||||
stu.study('数学')
|
||||
stu.watch_av()
|
||||
t = Teacher('骆昊', 38, '老叫兽')
|
||||
t = Teacher('骆昊', 38, '砖家')
|
||||
t.teach('Python程序设计')
|
||||
t.watch_av()
|
||||
|
||||
|
@ -636,7 +636,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
>**说明**:大家可以自己尝试在上面代码的基础上写一个简单的扑克游戏,例如21点(Black Jack),游戏的规则可以自己在网上找一找。
|
||||
>**说明:** 大家可以自己尝试在上面代码的基础上写一个简单的扑克游戏,例如21点(Black Jack),游戏的规则可以自己在网上找一找。
|
||||
|
||||
#### 案例3:工资结算系统
|
||||
|
|
@ -128,7 +128,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
####加载图像
|
||||
#### 加载图像
|
||||
|
||||
如果需要直接加载图像到窗口上,可以使用pygame中image模块的函数来加载图像,再通过之前获得的窗口对象的`blit`方法渲染图像,代码如下所示。
|
||||
|
||||
|
@ -164,7 +164,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
####实现动画效果
|
||||
#### 实现动画效果
|
||||
|
||||
说到[动画](https://zh.wikipedia.org/wiki/%E5%8A%A8%E7%94%BB)这个词大家都不会陌生,事实上要实现动画效果,本身的原理也非常简单,就是将不连续的图片连续的播放,只要每秒钟达到了一定的帧数,那么就可以做出比较流畅的动画效果。如果要让上面代码中的小球动起来,可以将小球的位置用变量来表示,并在循环中修改小球的位置再刷新整个窗口即可。
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
## 文件和异常
|
||||
|
||||
在实际开发中,常常需要对程序中的数据进行[持久化](https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E6%8C%81%E4%B9%85%E5%8C%96)操作,而实现数据持久化最直接简单的方式就是将数据保存到文件中。说到“文件”这个词,可能需要先科普一下关于[文件系统](https://zh.wikipedia.org/wiki/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F)的知识,对于这个概念,维基百科上给出了很好的诠释,这里不再浪费笔墨。
|
||||
实际开发中常常会遇到对数据进行[持久化](https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E6%8C%81%E4%B9%85%E5%8C%96)操作的场景,而实现数据持久化最直接简单的方式就是将数据保存到文件中。说到“文件”这个词,可能需要先科普一下关于[文件系统](https://zh.wikipedia.org/wiki/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F)的知识,但是这里我们并不浪费笔墨介绍这个概念,请大家自行通过维基百科进行了解。
|
||||
|
||||
在Python中实现文件的读写操作其实非常简单,通过Python内置的`open`函数,我们可以指定文件名、操作模式、编码信息等来获得操作文件的对象,接下来就可以对文件进行读写操作了。这里所说的操作模式是指要打开什么样的文件(字符文件还是二进制文件)以及做什么样的操作(读、写还是追加),具体的如下表所示。
|
||||
|
||||
|
@ -103,7 +103,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
要将文本信息写入文件文件也非常简单,在使用`open`函数时指定好文件名并将文件模式设置为`'w'`即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为`'a'`。如果要写入的文件不存在会自动创建文件而不是引发异常。下面的例子演示了如何将1-9999直接的素数分别写入三个文件中(1-99之间的素数保存在a.txt中,100-999之间的素数保存在b.txt中,1000-9999之间的素数保存在c.txt中)。
|
||||
要将文本信息写入文件文件也非常简单,在使用`open`函数时指定好文件名并将文件模式设置为`'w'`即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为`'a'`。如果要写入的文件不存在会自动创建文件而不是引发异常。下面的例子演示了如何将1-9999之间的素数分别写入三个文件中(1-99之间的素数保存在a.txt中,100-999之间的素数保存在b.txt中,1000-9999之间的素数保存在c.txt中)。
|
||||
|
||||
```Python
|
||||
from math import sqrt
|
||||
|
@ -174,14 +174,14 @@ if __name__ == '__main__':
|
|||
|
||||
```JSON
|
||||
{
|
||||
'name': '骆昊',
|
||||
'age': 38,
|
||||
'qq': 957658,
|
||||
'friends': ['王大锤', '白元芳'],
|
||||
'cars': [
|
||||
{'brand': 'BYD', 'max_speed': 180},
|
||||
{'brand': 'Audi', 'max_speed': 280},
|
||||
{'brand': 'Benz', 'max_speed': 320}
|
||||
"name": "骆昊",
|
||||
"age": 38,
|
||||
"qq": 957658,
|
||||
"friends": ["王大锤", "白元芳"],
|
||||
"cars": [
|
||||
{"brand": "BYD", "max_speed": 180},
|
||||
{"brand": "Audi", "max_speed": 280},
|
||||
{"brand": "Benz", "max_speed": 320}
|
||||
]
|
||||
}
|
||||
```
|
|
@ -32,7 +32,7 @@
|
|||
| \| | 分支 | foo\|bar | 可以匹配foo或者bar |
|
||||
| (?#) | 注释 | | |
|
||||
| (exp) | 匹配exp并捕获到自动命名的组中 | | |
|
||||
| (?<name>exp) | 匹配exp并捕获到名为name的组中 | | |
|
||||
| (? <name>exp) | 匹配exp并捕获到名为name的组中 | | |
|
||||
| (?:exp) | 匹配exp但是不捕获匹配的文本 | | |
|
||||
| (?=exp) | 匹配exp前面的位置 | \\b\\w+(?=ing) | 可以匹配I'm dancing中的danc |
|
||||
| (?<=exp) | 匹配exp后面的位置 | (?<=\\bdanc)\\w+\\b | 可以匹配I love dancing and reading中的第一个ing |
|
||||
|
@ -44,7 +44,7 @@
|
|||
| {M,N}? | 重复M到N次,但尽可能少重复 | | |
|
||||
| {M,}? | 重复M次以上,但尽可能少重复 | | |
|
||||
|
||||
> **说明:**如果需要匹配的字符是正则表达式中的特殊字符,那么可以使用\\进行转义处理,例如想匹配小数点可以写成\\.就可以了,因为直接写.会匹配任意字符;同理,想匹配圆括号必须写成\\(和\\),否则圆括号被视为正则表达式中的分组。
|
||||
> **说明:** 如果需要匹配的字符是正则表达式中的特殊字符,那么可以使用\\进行转义处理,例如想匹配小数点可以写成\\.就可以了,因为直接写.会匹配任意字符;同理,想匹配圆括号必须写成\\(和\\),否则圆括号被视为正则表达式中的分组。
|
||||
|
||||
### Python对正则表达式的支持
|
||||
|
||||
|
@ -64,7 +64,7 @@ Python提供了re模块来支持正则表达式相关操作,下面是re模块
|
|||
| re.I / re.IGNORECASE | 忽略大小写匹配标记 |
|
||||
| re.M / re.MULTILINE | 多行匹配标记 |
|
||||
|
||||
> **说明:**上面提到的re模块中的这些函数,实际开发中也可以用正则表达式对象的方法替代对这些函数的使用,如果一个正则表达式需要重复的使用,那么先通过compile函数编译正则表达式并创建出正则表达式对象无疑是更为明智的选择。
|
||||
> **说明:** 上面提到的re模块中的这些函数,实际开发中也可以用正则表达式对象的方法替代对这些函数的使用,如果一个正则表达式需要重复的使用,那么先通过compile函数编译正则表达式并创建出正则表达式对象无疑是更为明智的选择。
|
||||
|
||||
下面我们通过一系列的例子来告诉大家在Python中如何使用正则表达式。
|
||||
|
||||
|
@ -98,7 +98,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **提示**:上面在书写正则表达式时使用了“原始字符串”的写法(在字符串前面加上了r),所谓“原始字符串”就是字符串中的每个字符都是它原始的意义,说得更直接一点就是字符串中没有所谓的转义字符啦。因为正则表达式中有很多元字符和需要进行转义的地方,如果不使用原始字符串就需要将反斜杠写作\\\\,例如表示数字的\\d得书写成\\\\d,这样不仅写起来不方便,阅读的时候也会很吃力。
|
||||
> **提示:** 上面在书写正则表达式时使用了“原始字符串”的写法(在字符串前面加上了r),所谓“原始字符串”就是字符串中的每个字符都是它原始的意义,说得更直接一点就是字符串中没有所谓的转义字符啦。因为正则表达式中有很多元字符和需要进行转义的地方,如果不使用原始字符串就需要将反斜杠写作\\\\,例如表示数字的\\d得书写成\\\\d,这样不仅写起来不方便,阅读的时候也会很吃力。
|
||||
|
||||
#### 例子2:从一段文字中提取出国内手机号码。
|
||||
|
||||
|
@ -136,7 +136,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:上面匹配国内手机号的正则表达式并不够好,因为像14开头的号码只有145或147,而上面的正则表达式并没有考虑这种情况,要匹配国内手机号,更好的正则表达式的写法是:`(?<=\D)(1[38]\d{9}|14[57]\d{8}|15[0-35-9]\d{8}|17[678]\d{8})(?=\D)`,国内最近好像有19和16开头的手机号了,但是这个暂时不在我们考虑之列。
|
||||
> **说明:** 上面匹配国内手机号的正则表达式并不够好,因为像14开头的号码只有145或147,而上面的正则表达式并没有考虑这种情况,要匹配国内手机号,更好的正则表达式的写法是:`(?<=\D)(1[38]\d{9}|14[57]\d{8}|15[0-35-9]\d{8}|17[678]\d{8})(?=\D)`,国内最近好像有19和16开头的手机号了,但是这个暂时不在我们考虑之列。
|
||||
|
||||
#### 例子3:替换字符串中的不良内容
|
||||
|
||||
|
@ -155,7 +155,7 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
> **说明**:re模块的正则表达式相关函数中都有一个flags参数,它代表了正则表达式的匹配标记,可以通过该标记来指定匹配时是否忽略大小写、是否进行多行匹配、是否显示调试信息等。如果需要为flags参数指定多个值,可以使用[按位或运算符](http://www.runoob.com/python/python-operators.html#ysf5)进行叠加,如`flags=re.I | re.M`。
|
||||
> **说明:** re模块的正则表达式相关函数中都有一个flags参数,它代表了正则表达式的匹配标记,可以通过该标记来指定匹配时是否忽略大小写、是否进行多行匹配、是否显示调试信息等。如果需要为flags参数指定多个值,可以使用[按位或运算符](http://www.runoob.com/python/python-operators.html#ysf5)进行叠加,如`flags=re.I | re.M`。
|
||||
|
||||
#### 例子4:拆分长字符串
|
||||
|
|
@ -320,7 +320,7 @@ if __name__ == '__main__':
|
|||
|
||||
除了计算密集型任务,其他的涉及到网络、存储介质I/O的任务都可以视为I/O密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待I/O操作完成(因为I/O的速度远远低于CPU和内存的速度)。对于I/O密集型任务,如果启动多任务,就可以减少I/O等待时间从而让CPU高效率的运转。有一大类的任务都属于I/O密集型任务,这其中包括了我们很快会涉及到的网络应用和Web应用。
|
||||
|
||||
> **说明:**上面的内容和例子来自于[廖雪峰官方网站的《Python教程》](https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000),因为对作者文中的某些观点持有不同的看法,对原文的文字描述做了适当的调整。
|
||||
> **说明:** 上面的内容和例子来自于[廖雪峰官方网站的《Python教程》](https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000),因为对作者文中的某些观点持有不同的看法,对原文的文字描述做了适当的调整。
|
||||
|
||||
### 单线程+异步I/O
|
||||
|
||||
|
@ -485,5 +485,5 @@ if __name__ == '__main__':
|
|||
main()
|
||||
```
|
||||
|
||||
比较两段代码的执行结果(在我目前使用的MacBook上,上面的代码需要大概6秒左右的时间,而下面的代码只需要不到1秒的时间,再强调一次我们只是比较了运算的时间,不考虑列表创建及切片操作花费的时间),使用多进程后由于获得了更多的CPU执行时间以及更好的利用了CPU的多核特性,明显的减少了程序的执行时间,而且计算量越大效果越明显。当然,如果愿意还可以将多个进程部署在不同的计算机上,做成分布式进程,具体的做法就是通过multiprocessing.managers模块中提供的管理器将`Queue`对象通过网络共享出来(注册到网络上让其他计算机可以访问),这部分内容也留到爬虫的专题再进行讲解。
|
||||
比较两段代码的执行结果(在我目前使用的MacBook上,上面的代码需要大概6秒左右的时间,而下面的代码只需要不到1秒的时间,再强调一次我们只是比较了运算的时间,不考虑列表创建及切片操作花费的时间),使用多进程后由于获得了更多的CPU执行时间以及更好的利用了CPU的多核特性,明显的减少了程序的执行时间,而且计算量越大效果越明显。当然,如果愿意还可以将多个进程部署在不同的计算机上,做成分布式进程,具体的做法就是通过`multiprocessing.managers`模块中提供的管理器将`Queue`对象通过网络共享出来(注册到网络上让其他计算机可以访问),这部分内容也留到爬虫的专题再进行讲解。
|
||||
|
|
@ -38,8 +38,6 @@ TCP全称传输控制协议,它是基于IP提供的寻址和路由服务而建
|
|||
2. 流量控制(通过滑动窗口匹配数据发送者和接收者之间的传输速度)。
|
||||
3. 拥塞控制(通过RTT时间以及对滑动窗口的控制缓解网络拥堵)。
|
||||
|
||||
|
||||
|
||||
#### 网络应用模式
|
||||
|
||||
1. C/S模式和B/S模式。这里的C指的是Client(客户端),通常是一个需要安装到某个宿主操作系统上的应用程序;而B指的是Browser(浏览器),它几乎是所有图形化操作系统都默认安装了的一个应用软件;通过C或B都可以实现对S(服务器)的访问。关于二者的比较和讨论在网络上有一大堆的文章,在此我们就不再浪费笔墨了。
|
||||
|
@ -70,9 +68,9 @@ JSON的例子:
|
|||
|
||||
```JSON
|
||||
{
|
||||
'from': 'Alice',
|
||||
'to': 'Bob',
|
||||
'content': 'Will you marry me?'
|
||||
"from": "Alice",
|
||||
"to": "Bob",
|
||||
"content": "Will you marry me?"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -291,9 +289,129 @@ if __name__ == '__main__':
|
|||
|
||||
在这个案例中,我们使用了JSON作为数据传输的格式(通过JSON格式对传输的数据进行了序列化和反序列化的操作),但是JSON并不能携带二进制数据,因此对图片的二进制数据进行了Base64编码的处理。Base64是一种用64个字符表示所有二进制数据的编码方式,通过将二进制数据每6位一组的方式重新组织,刚好可以使用0~9的数字、大小写字母以及“+”和“/”总共64个字符表示从`000000`到`111111`的64种状态。[维基百科](https://zh.wikipedia.org/wiki/Base64)上有关于Base64编码的详细讲解,不熟悉Base64的读者可以自行阅读。
|
||||
|
||||
> **说明**:上面的代码主要为了讲解网络编程的相关内容因此并没有对异常状况进行处理,请读者自行添加异常处理代码来增强程序的健壮性。
|
||||
> **说明:** 上面的代码主要为了讲解网络编程的相关内容因此并没有对异常状况进行处理,请读者自行添加异常处理代码来增强程序的健壮性。
|
||||
|
||||
#### UDP套接字
|
||||
|
||||
传输层除了有可靠的传输协议TCP之外,还有一种非常轻便的传输协议叫做用户数据报协议,简称UDP。TCP和UDP都是提供端到端传输服务的协议,二者的差别就如同打电话和发短信的区别,后者不对传输的可靠性和可达性做出任何承诺从而避免了TCP中握手和重传的开销,所以在强调性能和而不是数据完整性的场景中(例如传输网络音视频数据),UDP可能是更好的选择。可能大家会注意到一个现象,就是在观看网络视频时,有时会出现卡顿,有时会出现花屏,这无非就是部分数据传丢或传错造成的。在Python中也可以使用UDP套接字来创建网络应用,对此我们不进行赘述,有兴趣的读者可以自行研究。
|
||||
|
||||
### 网络应用开发
|
||||
|
||||
#### 发送电子邮件
|
||||
|
||||
在即时通信软件如此发达的今天,电子邮件仍然是互联网上使用最为广泛的应用之一,公司向应聘者发出录用通知、网站向用户发送一个激活账号的链接、银行向客户推广它们的理财产品等几乎都是通过电子邮件来完成的,而这些任务应该都是由程序自动完成的。
|
||||
|
||||
就像我们可以用HTTP(超文本传输协议)来访问一个网站一样,发送邮件要使用SMTP(简单邮件传输协议),SMTP也是一个建立在TCP(传输控制协议)提供的可靠数据传输服务的基础上的应用级协议,它规定了邮件的发送者如何跟发送邮件的服务器进行通信的细节,而Python中的smtplib模块将这些操作简化成了几个简单的函数。
|
||||
|
||||
下面的代码演示了如何在Python发送邮件。
|
||||
|
||||
```Python
|
||||
from smtplib import SMTP
|
||||
from email.header import Header
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
|
||||
def main():
|
||||
# 请自行修改下面的邮件发送者和接收者
|
||||
sender = 'abcdefg@126.com'
|
||||
receivers = ['uvwxyz@qq.com', 'uvwxyz@126.com']
|
||||
message = MIMEText('用Python发送邮件的示例代码.', 'plain', 'utf-8')
|
||||
message['From'] = Header('王大锤', 'utf-8')
|
||||
message['To'] = Header('骆昊', 'utf-8')
|
||||
message['Subject'] = Header('示例代码实验邮件', 'utf-8')
|
||||
smtper = SMTP('smtp.126.com')
|
||||
# 请自行修改下面的登录口令
|
||||
smtper.login(sender, 'secretpass')
|
||||
smtper.sendmail(sender, receivers, message.as_string())
|
||||
print('邮件发送完成!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
如果要发送带有附件的邮件,那么可以按照下面的方式进行操作。
|
||||
|
||||
```Python
|
||||
from smtplib import SMTP
|
||||
from email.header import Header
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.image import MIMEImage
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
import urllib
|
||||
|
||||
|
||||
def main():
|
||||
# 创建一个带附件的邮件消息对象
|
||||
message = MIMEMultipart()
|
||||
|
||||
# 创建文本内容
|
||||
text_content = MIMEText('附件中有本月数据请查收', 'plain', 'utf-8')
|
||||
message['Subject'] = Header('本月数据', 'utf-8')
|
||||
# 将文本内容添加到邮件消息对象中
|
||||
message.attach(text_content)
|
||||
|
||||
# 读取文件并将文件作为附件添加到邮件消息对象中
|
||||
with open('/Users/Hao/Desktop/hello.txt', 'rb') as f:
|
||||
txt = MIMEText(f.read(), 'base64', 'utf-8')
|
||||
txt['Content-Type'] = 'text/plain'
|
||||
txt['Content-Disposition'] = 'attachment; filename=hello.txt'
|
||||
message.attach(txt)
|
||||
# 读取文件并将文件作为附件添加到邮件消息对象中
|
||||
with open('/Users/Hao/Desktop/汇总数据.xlsx', 'rb') as f:
|
||||
xls = MIMEText(f.read(), 'base64', 'utf-8')
|
||||
xls['Content-Type'] = 'application/vnd.ms-excel'
|
||||
xls['Content-Disposition'] = 'attachment; filename=month-data.xlsx'
|
||||
message.attach(xls)
|
||||
|
||||
# 创建SMTP对象
|
||||
smtper = SMTP('smtp.126.com')
|
||||
# 开启安全连接
|
||||
# smtper.starttls()
|
||||
sender = 'abcdefg@126.com'
|
||||
receivers = ['uvwxyz@qq.com']
|
||||
# 登录到SMTP服务器
|
||||
# 请注意此处不是使用密码而是邮件客户端授权码进行登录
|
||||
# 对此有疑问的读者可以联系自己使用的邮件服务器客服
|
||||
smtper.login(sender, 'secretpass')
|
||||
# 发送邮件
|
||||
smtper.sendmail(sender, receivers, message.as_string())
|
||||
# 与邮件服务器断开连接
|
||||
smtper.quit()
|
||||
print('发送完成!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
#### 发送短信
|
||||
|
||||
发送短信也是项目中常见的功能,网站的注册码、验证码、营销信息基本上都是通过短信来发送给用户的。在下面的代码中我们使用了[互亿无线](http://www.ihuyi.com/)短信平台(该平台为注册用户提供了50条免费短信以及常用开发语言发送短信的demo,可以登录该网站并在用户自服务页面中对短信进行配置)提供的API接口实现了发送短信的服务,当然国内的短信平台很多,读者可以根据自己的需要进行选择(通常会考虑费用预算、短信达到率、使用的难易程度等指标),如果需要在商业项目中使用短信服务建议购买短信平台提供的套餐服务。
|
||||
|
||||
```Python
|
||||
import urllib.parse
|
||||
import http.client
|
||||
import json
|
||||
|
||||
|
||||
def main():
|
||||
host = "106.ihuyi.com"
|
||||
sms_send_uri = "/webservice/sms.php?method=Submit"
|
||||
# 下面的参数需要填入自己注册的账号和对应的密码
|
||||
params = urllib.parse.urlencode({'account': '你自己的账号', 'password' : '你自己的密码', 'content': '您的验证码是:147258。请不要把验证码泄露给其他人。', 'mobile': '接收者的手机号', 'format':'json' })
|
||||
print(params)
|
||||
headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
|
||||
conn = http.client.HTTPConnection(host, port=80, timeout=30)
|
||||
conn.request('POST', sms_send_uri, params, headers)
|
||||
response = conn.getresponse()
|
||||
response_str = response.read()
|
||||
jsonstr = response_str.decode('utf-8')
|
||||
print(json.loads(jsonstr))
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
|
@ -76,7 +76,7 @@ Pillow中最为重要的是Image类,读取和处理图像都要通过这个类
|
|||
|
||||
```Python
|
||||
>>> image = Image.open('./res/guido.png')
|
||||
>>> image.rotata(180).show()
|
||||
>>> image.rotate(180).show()
|
||||
>>> image.transpose(Image.FLIP_LEFT_RIGHT).show()
|
||||
```
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
## 练习
|
||||
|
||||
### 练习清单
|
||||
|
||||
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赌博游戏。
|
File diff suppressed because one or more lines are too long
|
@ -1,121 +0,0 @@
|
|||
## 网络应用开发
|
||||
|
||||
### 发送电子邮件
|
||||
|
||||
在即时通信软件如此发达的今天,电子邮件仍然是互联网上使用最为广泛的应用之一,公司向应聘者发出录用通知、网站向用户发送一个激活账号的链接、银行向客户推广它们的理财产品等几乎都是通过电子邮件来完成的,而这些任务应该都是由程序自动完成的。
|
||||
|
||||
就像我们可以用HTTP(超文本传输协议)来访问一个网站一样,发送邮件要使用SMTP(简单邮件传输协议),SMTP也是一个建立在TCP(传输控制协议)提供的可靠数据传输服务的基础上的应用级协议,它规定了邮件的发送者如何跟发送邮件的服务器进行通信的细节,而Python中的smtplib模块将这些操作简化成了几个简单的函数。
|
||||
|
||||
下面的代码演示了如何在Python发送邮件。
|
||||
|
||||
```Python
|
||||
from smtplib import SMTP
|
||||
from email.header import Header
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
|
||||
def main():
|
||||
# 请自行修改下面的邮件发送者和接收者
|
||||
sender = 'abcdefg@126.com'
|
||||
receivers = ['uvwxyz@qq.com', 'uvwxyz@126.com']
|
||||
message = MIMEText('用Python发送邮件的示例代码.', 'plain', 'utf-8')
|
||||
message['From'] = Header('王大锤', 'utf-8')
|
||||
message['To'] = Header('骆昊', 'utf-8')
|
||||
message['Subject'] = Header('示例代码实验邮件', 'utf-8')
|
||||
smtper = SMTP('smtp.126.com')
|
||||
# 请自行修改下面的登录口令
|
||||
smtper.login(sender, 'secretpass')
|
||||
smtper.sendmail(sender, receivers, message.as_string())
|
||||
print('邮件发送完成!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
如果要发送带有附件的邮件,那么可以按照下面的方式进行操作。
|
||||
|
||||
```Python
|
||||
from smtplib import SMTP
|
||||
from email.header import Header
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.image import MIMEImage
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
import urllib
|
||||
|
||||
|
||||
def main():
|
||||
# 创建一个带附件的邮件消息对象
|
||||
message = MIMEMultipart()
|
||||
|
||||
# 创建文本内容
|
||||
text_content = MIMEText('附件中有本月数据请查收', 'plain', 'utf-8')
|
||||
message['Subject'] = Header('本月数据', 'utf-8')
|
||||
# 将文本内容添加到邮件消息对象中
|
||||
message.attach(text_content)
|
||||
|
||||
# 读取文件并将文件作为附件添加到邮件消息对象中
|
||||
with open('/Users/Hao/Desktop/hello.txt', 'rb') as f:
|
||||
txt = MIMEText(f.read(), 'base64', 'utf-8')
|
||||
txt['Content-Type'] = 'text/plain'
|
||||
txt['Content-Disposition'] = 'attachment; filename=hello.txt'
|
||||
message.attach(txt)
|
||||
# 读取文件并将文件作为附件添加到邮件消息对象中
|
||||
with open('/Users/Hao/Desktop/汇总数据.xlsx', 'rb') as f:
|
||||
xls = MIMEText(f.read(), 'base64', 'utf-8')
|
||||
xls['Content-Type'] = 'application/vnd.ms-excel'
|
||||
xls['Content-Disposition'] = 'attachment; filename=month-data.xlsx'
|
||||
message.attach(xls)
|
||||
|
||||
# 创建SMTP对象
|
||||
smtper = SMTP('smtp.126.com')
|
||||
# 开启安全连接
|
||||
# smtper.starttls()
|
||||
sender = 'abcdefg@126.com'
|
||||
receivers = ['uvwxyz@qq.com']
|
||||
# 登录到SMTP服务器
|
||||
# 请注意此处不是使用密码而是邮件客户端授权码进行登录
|
||||
# 对此有疑问的读者可以联系自己使用的邮件服务器客服
|
||||
smtper.login(sender, 'secretpass')
|
||||
# 发送邮件
|
||||
smtper.sendmail(sender, receivers, message.as_string())
|
||||
# 与邮件服务器断开连接
|
||||
smtper.quit()
|
||||
print('发送完成!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
### 发送短信
|
||||
|
||||
发送短信也是项目中常见的功能,网站的注册码、验证码、营销信息基本上都是通过短信来发送给用户的。在下面的代码中我们使用了[互亿无线](http://www.ihuyi.com/)短信平台(该平台为注册用户提供了50条免费短信以及常用开发语言发送短信的demo,可以登录该网站并在用户自服务页面中对短信进行配置)提供的API接口实现了发送短信的服务,当然国内的短信平台很多,读者可以根据自己的需要进行选择(通常会考虑费用预算、短信达到率、使用的难易程度等指标),如果需要在商业项目中使用短信服务建议购买短信平台提供的套餐服务。
|
||||
|
||||
```Python
|
||||
import urllib.parse
|
||||
import http.client
|
||||
import json
|
||||
|
||||
|
||||
def main():
|
||||
host = "106.ihuyi.com"
|
||||
sms_send_uri = "/webservice/sms.php?method=Submit"
|
||||
# 下面的参数需要填入自己注册的账号和对应的密码
|
||||
params = urllib.parse.urlencode({'account': '你自己的账号', 'password' : '你自己的密码', 'content': '您的验证码是:147258。请不要把验证码泄露给其他人。', 'mobile': '接收者的手机号', 'format':'json' })
|
||||
print(params)
|
||||
headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
|
||||
conn = http.client.HTTPConnection(host, port=80, timeout=30)
|
||||
conn.request('POST', sms_send_uri, params, headers)
|
||||
response = conn.getresponse()
|
||||
response_str = response.read()
|
||||
jsonstr = response_str.decode('utf-8')
|
||||
print(json.loads(jsonstr))
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 176 KiB |
|
@ -6,8 +6,13 @@ Version: 0.1
|
|||
Author: 骆昊
|
||||
Date: 2018-02-26
|
||||
|
||||
请将该文件命名为hello.py并在终端中通过下面的命令运行它
|
||||
请将该文件命名为hello.py
|
||||
|
||||
使用Windows的小伙伴可以在命令行提示下通过下面的命令运行该程序
|
||||
python hello.py
|
||||
|
||||
对于使用Linux或macOS的小伙伴可以打开终端并键入下面的命令来运行程序
|
||||
python3 hello.py
|
||||
"""
|
||||
|
||||
print('hello, world!')
|
|
@ -5,7 +5,6 @@ Version: 0.1
|
|||
Author: 骆昊
|
||||
Date: 2018-02-27
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
radius = float(input('请输入圆的半径: '))
|
|
@ -1,10 +1,10 @@
|
|||
"""
|
||||
百分制成绩转等级制成绩
|
||||
90分以上 --> A
|
||||
80分~89分 --> B
|
||||
70分~79分 --> C
|
||||
60分~69分 --> D
|
||||
60分以下 --> E
|
||||
90分以上,输出A
|
||||
80分~89分,输出B
|
||||
70分~79分,输出C
|
||||
60分~69分,输出D
|
||||
60分以下,输出E
|
||||
|
||||
Version: 0.1
|
||||
Author: 骆昊
|
|
@ -5,7 +5,6 @@ Version: 0.1
|
|||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
from random import randint
|
||||
|
||||
face = randint(1, 6)
|
|
@ -6,7 +6,6 @@ Version: 0.1
|
|||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
a = float(input('a = '))
|
|
@ -5,7 +5,6 @@ Version: 0.1
|
|||
Author: 骆昊
|
||||
Date: 2018-02-28
|
||||
"""
|
||||
|
||||
# import getpass
|
||||
# from getpass import getpass
|
||||
# from getpass import *
|
|
@ -8,6 +8,5 @@ Date: 2018-03-01
|
|||
|
||||
sum = 0
|
||||
for x in range(1, 101):
|
||||
if x % 2 == 0:
|
||||
sum += x
|
||||
sum += x
|
||||
print(sum)
|
|
@ -5,7 +5,6 @@ Version: 0.1
|
|||
Author: 骆昊
|
||||
Date: 2018-03-01
|
||||
"""
|
||||
|
||||
from math import sqrt
|
||||
|
||||
num = int(input('请输入一个正整数: '))
|
|
@ -6,8 +6,7 @@ Author: 骆昊
|
|||
Date: 2018-03-01
|
||||
"""
|
||||
|
||||
sum = 0
|
||||
num = 2
|
||||
sum, num = 0, 2
|
||||
while num <= 100:
|
||||
sum += num
|
||||
num += 2
|
|
@ -13,5 +13,3 @@ for x in range(0, 20):
|
|||
z = 100 - x - y
|
||||
if 5 * x + 3 * y + z / 3 == 100:
|
||||
print('公鸡: %d只, 母鸡: %d只, 小鸡: %d只' % (x, y, z))
|
||||
|
||||
# 要理解程序背后的算法 - 穷举法
|
|
@ -11,7 +11,6 @@ Version: 0.1
|
|||
Author: 骆昊
|
||||
Date: 2018-03-02
|
||||
"""
|
||||
|
||||
from random import randint
|
||||
|
||||
money = 1000
|
|
@ -10,5 +10,5 @@ Date: 2018-03-02
|
|||
a = 0
|
||||
b = 1
|
||||
for _ in range(20):
|
||||
(a, b) = (b, a + b)
|
||||
a, b = b, a + b
|
||||
print(a, end=' ')
|
|
@ -7,7 +7,6 @@ Version: 0.1
|
|||
Author: 骆昊
|
||||
Date: 2018-03-02
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
answer = random.randint(1, 100)
|
|
@ -10,7 +10,6 @@ Date: 2018-03-02
|
|||
import time
|
||||
import math
|
||||
|
||||
start = time.clock()
|
||||
for num in range(1, 10000):
|
||||
sum = 0
|
||||
for factor in range(1, int(math.sqrt(num)) + 1):
|
||||
|
@ -20,7 +19,3 @@ for num in range(1, 10000):
|
|||
sum += num / factor
|
||||
if sum == num:
|
||||
print(num)
|
||||
end = time.clock()
|
||||
print("执行时间:", (end - start), "秒")
|
||||
|
||||
# 通过比较上面两种不同的解决方案的执行时间 意识到优化程序的重要性
|
|
@ -28,7 +28,7 @@ class Student(object):
|
|||
if self.age < 18:
|
||||
print('%s只能观看《熊出没》.' % self.name)
|
||||
else:
|
||||
print('%s正在观看岛国爱情动作片.' % self.name)
|
||||
print('%s正在观看岛国大电影.' % self.name)
|
||||
|
||||
|
||||
def main():
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue