Python读书笔记

python 专栏收录该内容
5 篇文章 1 订阅

Python读书笔记

目录

1. 总览 12

1.1. Python编程基础 12

1.2. Python编程规范 12

1.3. 设计模式(基于python实现) 12

1.4. 重构,改善既有代码的设计 12

1.5. Python web 应用框架: Django 12

1.6. Python 机器学习框架:tensorflow 12

2. 拷机测试服务整体结构 12

2.1. 业务结构 12

2.2. 技术结构(监控) 13

2.3. 技术结构(图像) 13

2.4. 技术选型 14

2.5. 运维模型 14

2.6. 工具选择 15

3. 协议测试用例自动生成整体结构 15

3.1. 业务结构 15

3.2. 技术结构 15

3.3. 技术选型 15

3.4. 运维模型 15

3.5. 工具选择 15

4. python基础知识 15

4.1. Python底层是用什么语言实现的? 15

4.2. Python关键字(保留字)一览表 16

4.3. Python内置函数一览表 17

4.4. Python三目运算符(三元运算符)用法详解 17

4.5. Python 内置的四种常用数据结构 20

4.6. Python lambda表达式(匿名函数)及用法 20

4.7. Python面向对象编程 24

4.8. Python异常处理机制 24

4.9. Python 上下文管理器 25

4.10. Python线程池及其原理和应用 26

4.11. Python网络编程 28

4.12. 经验案例 31

4.13. 参考书目 31

4.13.1. Magnus《Python基础教程(第2版)》 31

4.13.2. Wesley《Python核心教程(第3版)》 31

4.13.3. Thomas《算法导论》 31

4.13.4. Micha《Python高性能编程》 31

4.13.5. Jon《编程珠玑(第2版)》 31

4.13.6. Robert《代码整洁之道》 31

4.14. 参考资料 31

4.14.1. Python编程基础 31

5. Python编码工具 32

5.1. Sublime Text 32

5.2. Pycharm 32

5.3. VS Code0 32

5.4. 测试部-云函数(基于VS Code) 32

5.5. 阿里云-云开发平台(基于VS Code) 32

5.6. 经验案例 32

5.7. 参考书目 32

5.8. 参考资料 32

6. Python源码剖析 32

6.1. Python源码剖析—编译Pyhton 32

6.2. Python对象初探(Python内建对象) 32

6.3. Python中的整数对象(Python内建对象) 32

6.4. Python中的字符对象(Python内建对象) 32

6.5. Python中的List对象(Python内建对象) 32

6.6. Python中的Dict对象(Python内建对象) 33

6.7. 最简单的Python模拟—Small Python(Python内建对象) 33

6.8. Python的编译结果—Code对象与pyc文件(python虚拟机) 33

6.9. Python虚拟机框架(python虚拟机) 33

6.10. Python虚拟机中的一般表达式(python虚拟机) 33

6.11. Python虚拟机中的控制流(python虚拟机) 33

6.12. Python虚拟机中的函数机制(python虚拟机) 33

6.13. Python虚拟机中的类机制(python虚拟机) 33

6.14. Python运行环境初始化(python高级话题) 33

6.15. Python模块的动态加载机制(python高级话题) 33

6.16. Python多线程机制(python高级话题) 33

6.17. Python内存管理机制(python高级话题) 33

6.18. 经验案例 33

6.19. 参考书目 33

6.19.1. 陈儒《Python源码剖析》 34

6.20. 参考资料 34

6.20.1. CPython源码 34

7. Python编码规范 34

7.1. 行长度 34

7.2. 括号 35

7.3. 缩进 36

7.4. 注释 37

7.5. 类 41

7.6. TODO注释 42

7.7. 命名 43

7.8. Main 44

7.1. 经验案例 45

7.2. 参考书目 45

7.3. 参考资料 45

7.3.1. PEP 8 – Style Guide for Python Code 45

7.3.2. Python 编码规范(Google) 45

8. 软件建模与设计 45

8.1. UML类图 45

8.2. UML时序图 52

8.2.1. 角色 52

8.2.2. 对象 52

8.2.3. 生命线 52

8.2.4. 控制焦点 53

8.2.5. 消息 53

8.2.6. 自关联消息 53

8.3. 经验案例 56

8.4. 参考书目 56

8.4.1. Hassan《软件建模与设计》 56

8.4.2. George《分布式系统 概念与设计》 56

8.4.3. Martin《架构即未来》 56

8.4.4. Martin《架构真经》 56

8.4.5. Martin《企业IT架构转型之道》 56

8.4.6. Richard《面向对象程序设计》 56

8.4.7. Brendan《分布式系统设计》 56

8.5. 参考资料 56

9. 设计模式 56

9.1. 概览 56

9.2. 创建型 59

9.2.1. Factory Method(工厂方法) 59

9.2.2. Abstract Factory(抽象工厂) 61

9.2.3. Builder(建造者) 63

9.2.4. Singleton(单例) 65

9.3. 结构型 66

9.3.1. Proxy(代理) 66

9.4. 行为型 67

9.4.1. Template Method模板方法 67

9.4.2. Command(命令) 68

9.5. 经验案例 70

9.6. 参考书目 70

9.6.1. Erich《设计模式》 70

9.6.2. 程杰《大话设计模式》 70

9.7. 参考资料 70

10. 代码重构 71

10.1. 引言 71

10.2. 为何重构 71

10.3. 代码的坏味道 74

10.4. 构筑测试体系 75

10.5. 经验案例 75

10.6. 参考书目 75

10.6.1. 阿瑟诺维斯基《代码重构》 75

10.7. 参考资料 76

11. 操作系统 76

11.1. 经验案例 76

11.2. 参考书目 76

11.2.1. 鸟哥《Linux 私房菜》 76

11.2.2. Randal《深入理解计算机系统》 76

11.2.3. Neil《Linux程序设计》 76

11.2.4. Alfred《编译原理》 76

11.3. 参考资料 76

12. 网络安全 76

12.1. 经验案例 76

12.2. 参考书目 76

12.3. 参考资料 76

13. 网络体系 76

13.1. 经验案例 76

13.2. 参考书目 77

13.2.1. David《HTTP 权威指南》 77

13.3. 参考资料 77

14. 数据库 77

14.1. SQL数据库原生 77

14.1.1. MySQL 77

14.1.2. SQLite 78

14.2. ORM 78

14.2.1. SQLAlchemy 78

14.3. 对象存储服务 80

14.3.1. MinIO 80

14.4. 内存存储服务 80

14.4.1. Redis 80

14.5. 经验案例 80

14.5.1. 视频会议系统的状态监控服务 –
通信模块&数据库读写模块部分经验案例 80

14.5.2. SQLAlchemy–Python下的ORM工具使用经验案例 80

14.6. 参考书目 80

14.6.1. Abrahan《数据库系统概念》 80

14.6.2. Schwartz《高性能MySQL》 80

14.7. 参考资料 80

15. web框架 80

15.1. Django 80

15.1.1. 这份文档是如何组织的 81

15.1.2. 快速入门 81

15.2. Flask 82

15.3. 经验案例 82

15.4. 参考书目 82

15.5. 参考资料 82

16. 运维模型 83

16.1. SRE google运维 83

16.2. 管理kubernetes(k8s) 83

16.3. Docker 83

16.4. 经验案例 83

16.5. 参考书目 83

16.5.1. Brendan《管理Kubernetes》 83

16.5.2. Sean《Docker即学即用》 83

16.5.3. Betsy《SRE Google运维解密》 83

16.6. 参考资料 83

17. 机器学习理论资料 83

17.1. 规则方法 83

17.2. 统计方法 83

17.3. 经验案例 83

17.4. 参考书目 83

17.4.1. Ian《Deep Learning》 84

17.4.2. Richard《现代控制系统(第12版)》 84

17.4.3. Peter《机器学习实战》 84

17.4.4. 美团算法团队《美团机器学习实践》 84

17.4.5. 李航《统计学习方法》 84

17.5. 参考资料 84

18. 机器学习框架 84

18.1. tensorflow 84

18.1.1. 简介 84

18.1.2. MNIST机器学习入门 87

18.2. 经验案例 94

18.2.1. 基于Tensorflow对MNIST数据集进行分类 94

18.2.2. 机器学习导论(培训材料) 94

18.3. 参考书目 94

18.4. 参考资料 94

19. python测试工具 95

19.1. selenium 95

19.2. monkeyRunner 95

19.3. airtest 95

19.4. pytest 95

19.5. 经验案例 95

19.6. 参考书目 95

19.6.1. James《Google 软件测试之道》 95

19.6.2. Ron《软件测试》 95

19.7. 参考资料 95

20. python库 95

20.1. 网络库 95

20.1.1. 网络库 ---- requests 95

20.1.2. 底层网络接口 ---- socket 95

20.1.3. asyncio的HTTP客户端/服务器(PEP-3156) ---- aiohttp 96

20.2. 网络爬虫框架 96

20.3. HTML/XML解析器 96

20.4. 经验案例 96

20.5. 参考书目 96

20.6. 参考资料 96

20.6.1. https://www.python.org/ 96

21. 参考资料 96

Python之禅

The Zen of Python, by Tim Peters

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编程规范

设计模式(基于python实现)

重构,改善既有代码的设计

Python web 应用框架: Django(https://docs.djangoproject.com/en/3.1/)

Python 机器学习框架:tensorflow(https://tensorflow.google.cn/)

拷机测试服务整体架构

业务结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yddDSb4G-1614078116972)(media/4b870aeb92340fd0d3ed7ea93bb25f9b.png)]

技术结构(监控)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9OK09j3b-1614078116975)(media/b31fa54351dfa9daec0dca2b5843f8a3.png)]

技术结构(图像)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-byI4YJI1-1614078116975)(media/c74117b6c2e2522d976625cd8f7cf631.png)]

技术选型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYm77k2S-1614078116977)(media/ea1ce586b569513ed30f5953c5bb0d9a.png)]

运维模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-73xPnDHV-1614078116978)(media/b0a887182c49715367d78d70bc47344d.png)]

工具选择

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YyhNNTPH-1614078116979)(media/24660aa51cb237297d60df58c580e612.png)]

协议测试用例自动生成整体架构

业务结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y39WC0cL-1614078116980)(media/4e92ff1d31191e46ade9699a5df546b8.png)]

技术结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yVztp0B3-1614078116980)(media/a38ce3a2e46985efddbfeb06d2c7d4de.png)]

技术选型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rdc0sJS5-1614078116981)(media/75410910029fa333d7d48d183c2bd26b.png)]

运维模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQ9ZGbbm-1614078116981)(media/9f6f3c8359b8aa1b177de0efb4f91d3d.png)]

工具选择

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DQHopmLK-1614078116982)(media/75410910029fa333d7d48d183c2bd26b.png)]

音视频自动化测试整体架构

业务结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-481WIvqc-1614078116982)(media/587839b40dcd260604b263a91d95e23a.png)]

技术结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yunfX6NQ-1614078116983)(media/cf8db666345392dc09b36bcd5470e791.png)]

技术选型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1yz0lsvo-1614078116983)(media/75410910029fa333d7d48d183c2bd26b.png)]

运维模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7CF4H9ZB-1614078116984)(media/9f6f3c8359b8aa1b177de0efb4f91d3d.png)]

工具选择

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dwcubey0-1614078116984)(media/75410910029fa333d7d48d183c2bd26b.png)]

python基础知识

Python底层是用什么语言实现的?

确切地说,本教程介绍的是用 C 语言编写实现的
Python,又称为 CPython。平时我们所讨论的
Python,指的其实就是 CPython。
随着编程语言的不断发展,Python 的实现方式也发生了变化,除了用 C
语言实现外,Python 还有其他的实现方式。例如,用
Java 语言实现的 Python 称为 JPython,用 .net
实现的 Python 称为 IronPython 等等。

Python 的这些实现方式虽然诞生比 CPython
晚,但一直在努力地跟上主流,并在不同的生产环境中不断地使用并推广 Python。

Python 的实现方式有很多种,Python 官网上介绍了 20 多种语言变体、方言或 C
语言之外的 Python
解释器实现。其中一些只是实现了语言核心语法、功能和内置扩展的一个子集,但至少有几个与
CPython
几乎完全兼容。更重要的是,在这些不同的实现方式中,虽然有些知识玩具项目或实验,但大部分都是为了解决某些实际问题而创建的,这些问题要么使用
CPython 无法解决,要么需要开发人员花费巨大的精力,这里举几个例子:

  • 在嵌入式系统中运行 Python 代码。

  • 与运行框架(如 Java 或 .NET)或其他语言做代码集成。

  • 在 Web 浏览器中运行 Python 代码。

Python关键字(保留字)一览表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uSwMY3RF-1614078116990)(media/2d8e94bfc68473b5c117e4f40468e284.png)]

Python内置函数一览表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3cgqJPDQ-1614078116990)(media/0c415fc85b8b4ac15f265709b026d1cd.png)]

Python三目运算符(三元运算符)用法详解

Python 可通过 if
语句来实现三目运算符的功能,因此可以近似地把这种 if
语句当成三目运算符。作为三目运算符的 if 语句的语法格式如下:

True_statements if expression else False_statements

三目运算符的规则是:先对逻辑表达式 expression 求值,如果逻辑表达式返回
True,则执行并返回 True_statements 的值;如果逻辑表达式返回 False,则执行并返回
False_statements 的值。看如下代码:

  1. a = 5

  2. b = 3

  3. st = “a大于b” if a > b else “a不大于b”

  4. # 输出"a大于b"

  5. print(st)

实际上,如果只是为了在控制台输出提示信息,还可以将上面的三目运算符表达式改为如下形式:

  1. # 输出"a大于b"

  2. print(“a大于b”) if a > b else print(“a不大于b”)

Python 允许在三目运算符的 True_statements 或 False_statements
中放置多条语句。Python 主要支持以下两种放置方式:

1.多条语句以英文逗号隔开:每条语句都会执行,程序返回多条语句的返回值组成的元组。

2.多条语句以英文分号隔开:每条语句都会执行,程序只返回第一条语句的返回值。
先看第一种情形,使用如下代码:

  1. # 第一个返回值部分使用两条语句,逗号隔开

  2. st = print(“crazyit”), ‘a大于b’ if a > b else “a不大于b”

  3. print(st)

上面程序中 True_statements 为
print(“crazyit”),‘a大于b’,这两条语句都会执行,程序将会返回这两条语句的返回值组成的元组。由于
print() 函数没有返回值,相当于它的返回值是 None。运行上面代码,将看到如下结果:

crazyit
(None,‘a大于b’)

如果将上面语句中的逗号改为分号,将逗号之后的语句改为赋值语句,即写成如下形式:

  1. # 第一个返回值部分使用两条语句,分号隔开

  2. st = print(“crazyit”); x = 20 if a > b else “a不大于b”

  3. print(st)

  4. print(x)

此时虽然 True_statements 包含两条语句,但程序只会返回第一条语句 print(”crazyit”)
的返回值,该语句同样返回 None,因此相当于 str 的返回值为
None。运行上面代码,将看到如下结果:

crazyit
None
20

需要指出的是,三目运算符支持嵌套,通过嵌套三目运算符,可以执行更复杂的判断。例如,下面代码需要判断
c、d 两个变量的大小关系:

  1. c = 5

  2. d = 5

  3. # 下面将输出c等于d

  4. print(“c大于d”) if c > d else (print(“c小于d”) if c <
    d else print(“c等于d”))

上面代码首先对 c>d 求值,如果该表达式为
True,程序将会执行并返回第一个表达式:print(”c大于d”);否则系统将会计算 else
后面的内容:(print(“c小于d”) if c < d else
print(“c等于d”)),这个表达式又是一个嵌套的三目运算符表达式。注意,进入该表达式时只剩下“c小于d”或“c等于d”两种情况,因此该三目运算符再次判断
c<d,如果该表达式为
True,将会输出“c小于d”;否则只剩下“c等于d”一种情况,自然就输出该字符串了。

Python 内置的四种常用数据结构

Python
内置的四种常用数据结构:列表(list)、元组(tuple)、字典(dict)以及集合(set)

这四种数据结构一但都可用于保存多个数据项,这对于编程而言是非常重要的,因为程序不仅需要使用单个变量来保存数据,还需要使用多种数据结构来保存大量数据,而列表、元组、字典和集合就可满足保存大量数据的需求。

列表(list)和元组(tuple)比较相似,它们都按顺序保存元素,每个元素都有自己的索引,因此列表和元组都可通过索引访问元素。二者的区别在于元组是不可修改的,但列表是可修改的。

字典(dict)和集合(set)类似,它们存储的数据都是无序的,其中字典是用 key-value
的形式保存数据。

Python lambda表达式(匿名函数)及用法

lambda
表达式(又称匿名函数)是现代编程语言争相引入的一种语法,如果说函数是命名的、方便复用的代码块,那么
lambda 表达式则是功能更灵活的代码块,它可以在程序中被传递和调用。

回顾《Python函数高级用法》一节中,get_math_func()
函数将返回三个局部函数之一。该函数代码如下:

def get_math_func(type) :
# 定义三个局部函数
# 返回局部函数
if type == “square” :
return square
if type == “cube” :
return cube
else:
return factorial

由于局部函数的作用域默认仅停留在其封闭函数之内,因此这三个局部函数的函数名的作用太有限了,即仅仅是在程序的
if 语句中作为返回值使用。一旦离开了 get_math_func()
函数体,这三个局部函数的函数名就失去了意义。
既然局部函数的函数名没有太大的意义,那么就考虑使用 lambda
表达式来简化局部函数的写法。

使用 lambda 表达式代替局部函数

如果使用 lambda 表达式来简化 get_math_func() 函数,则可以将程序改写成如下形式:

  1. def get_math_func(type) :

  2. result=1

  3. # 该函数返回的是Lambda表达式

  4. if type == ‘square’:

  5. return lambda n: n * n # ①

  6. elif type == ‘cube’:

  7. return lambda n: n * n * n # ②

  8. else:

  9. return lambda n: (1 + n) * n / 2 # ③

  10. # 调用get_math_func(),程序返回一个嵌套函数

  11. math_func = get_math_func(“cube”)

  12. print(math_func(5)) # 输出125

  13. math_func = get_math_func(“square”)

  14. print(math_func(5)) # 输出25

  15. math_func = get_math_func(“other”)

  16. print(math_func(5)) # 输出15.0

在上面代码中,return 后面的部分使用 lambda 关键字定义的就是 lambda
表达式,Python 要求 lambda
表达式只能是单行表达式。

注意:由于 lambda 表达式只能是单行表达式,不允许使用更复杂的函数形式,因此上面 ③
号代码处改为计算 1+2+3+…+n 的总和。
lambda 表达式的语法格式如下:

lambda [parameter_list] : 表达式

从上面的语法格式可以看出 lambda 表达式的几个要点:

  • lambda 表达式必须使用 lambda 关键字定义。

  • 在 lambda
    关键字之后、冒号左边的是参数列表,可以没有参数,也可以有多个参数。如果有多个参数,则需要用逗号隔开,冒号右边是该
    lambda 表达式的返回值。
    实际上,lambda 表达式的本质就是匿名的、单行函数体的函数。因此,lambda
    表达式可以写成函数的形式。
    例如,对于如下 lambda 表达式:

lambda x , y:x + y

可改写为如下函数形式:

def add(x, y):
return x+ y

上面定义函数时使用了简化语法:当函数体只有一行代码时,可以直接把函数体的代码放在与函数头同一行。

总体来说,函数比 lambda 表达式的适应性更强,lambda
表达式只能创建简单的函数对象(它只适合函数体为单行的情形)。但 lambda
表达式依然有如下两个用途:

对于单行函数,使用 lambda 表达式可以省去定义函数的过程,让代码更加简洁。

对于不需要多次复用的函数,使用 lambda 表达式可以在用完之后立即释放,提高了性能。

下面代码示范了通过 lambda 表达式来调用 Python 内置的 map() 函数:

  1. # 传入计算平方的lambda表达式作为参数

  2. x = map(lambda x: x*x , range(8))

  3. print([e for e in x]) # [0, 1, 4, 9, 16, 25, 36, 49]

  4. # 传入计算平方的lambda表达式作为参数

  5. y = map(lambda x: x*x if x % 2 == 0 else 0, range(8))

  6. print([e for e in y]) # [0, 0, 4, 0, 16, 0, 36, 0]

正如从上面代码所看到的,内置的 map()
函数的第一个参数需要传入函数,此处传入了函数的简化形式:lambda
表达式,这样程序更加简洁,而且性能更好。

本节所介绍的 lambda 表达式是 Python 编程的核心机制之一。Python
语言既支持面向过程编程,也支持面向对象编程。而 lambda 表达式是 Python
面向过程编程的语法基础,因此读者必须引起重视。
Python 的 lambda 表达式只是单行函数的简化版本,因此 lambda
表达式的功能比较简单。

Python面向对象编程

Python 就被设计成支持面向对象的编程语言,因此 Python
完全能以面向对象的方式编程。而且 Python
的面向对象比较简单,它不像其他面向对象语言提供了大量繁杂的面向对象特征,它致力于提供简单、够用的语法功能。

正因为如此,在 Python 中创建一个类和对象都很容易。Python
支持面向对象的三大特征:封装、继承和多态,子类继承父类同样可以继承到父类的变量和方法。

Python异常处理机制

异常机制已经成为判断一门编程语言是否成熟的标准,除传统的像 C
语言没有提供异常机制之外,目前主流的编程语言如 Python、 Java、 Kotlin
等都提供了成熟的异常机制。
异常机制可以使程序中的异常处理代码和正常业务代间分离,保证程序代码更加优雅,并可以提高程序的健壮性。

Python 的异常机制主要依赖 try 、except 、else、finally 和 raise 五个关键字:

try 关键字后缩进的代码块简称 try 块,它里面放置的是可能引发异常的代码;

在 except 后对应的是异常类型和一个代码块,用于表明该 except
块处理这种类型的代码块;

在多个 except 块之后可以放一个 else 块,表明程序不出现异常时还要执行 else 块;

最后还可以跟一个 finally 块,finally 块用于回收在 try
块里打开的物理资源,异常机制会保证 finally 块总被执行;

raise 用于引发一个实际的异常,raise
可以单独作为语句使用,引发一个具体的异常对象;

Python 上下文管理器

在介绍 with as
语句时讲到,该语句操作的对象必须是上下文管理器。那么,到底什么是上下文管理器呢?

简单的理解,同时包含 _enter_() 和 _exit_()
方法的对象就是上下文管理器。也就是说,上下文管理器必须实现如下两个方法:

  1. _enter_(self):进入上下文管理器自动调用的方法,该方法会在 with as
    代码块执行之前执行。如果 with 语句有 as子句,那么该方法的返回值会被赋值给 as
    子句后的变量;该方法可以返回多个值,因此在 as
    子句后面也可以指定多个变量(多个变量必须由“()”括起来组成元组)。

  2. _exit_(self, exc_type, exc_value,
    exc_traceback):退出上下文管理器自动调用的方法。该方法会在 with as
    代码块执行之后执行。如果 with as
    代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为 None:如果
    with as 代码块因为异常而中止,程序也自动调用该方法,使用 sys.exc_info
    得到的异常信息将作为调用该方法的参数。
    当 with as 操作上下文管理器时,就会在执行语句体之前,先执行上下文管理器的
    _enter_() 方法,然后再执行语句体,最后执行 _exit_() 方法。
    构建上下文管理器,常见的有 2 种方式:基于类实现和基于生成器实现。

基于类的上下文管理器

通过上面的介绍不难发现,只要一个类实现了 _enter_() 和 _exit_() 这 2
个方法,程序就可以使用 with as 语句来管理它,通过 _exit_()
方法的参数,即可判断出 with
代码块执行时是否遇到了异常。其实,上面程序中的文件对象也实现了这两个方法,因此可以接受
with as 语句的管理。

Python线程池及其原理和应用

系统启动一个新线程的成本是比较高的,因为它涉及与操作系统的交互。在这种情形下,使用线程池可以很好地提升性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池。

线程池在系统启动时即创建大量空闲的线程,程序只要将一个函数提交给线程池,线程池就会启动一个空闲的线程来执行它。当该函数执行结束后,该线程并不会死亡,而是再次返回到线程池中变成空闲状态,等待执行下一个函数。

此外,使用线程池可以有效地控制系统中并发线程的数量。当系统中包含有大量的并发线程时,会导致系统性能急剧下降,甚至导致
Python
解释器崩溃,而线程池的最大线程数参数可以控制系统中并发线程的数量不超过此数。

线程池的使用

线程池的基类是 concurrent.futures 模块中的 Executor,Executor 提供了两个子类,即
ThreadPoolExecutor 和 ProcessPoolExecutor,其中 ThreadPoolExecutor
用于创建线程池,而 ProcessPoolExecutor 用于创建进程池。
如果使用线程池/进程池来管理并发编程,那么只要将相应的 task
函数提交给线程池/进程池,剩下的事情就由线程池/进程池来搞定。
Exectuor 提供了如下常用方法:

submit(fn, *args, **kwargs):将 fn 函数提交给线程池。*args 代表传给 fn
函数的参数,*kwargs 代表以关键字参数的形式为 fn 函数传入参数。

map(func, *iterables, timeout=None, chunksize=1):该函数类似于全局函数
map(func, *iterables),只是该函数将会启动多个线程,以异步方式立即对 iterables
执行 map 处理。

shutdown(wait=True):关闭线程池。
程序将 task 函数提交(submit)给线程池后,submit 方法会返回一个 Future
对象,Future
类主要用于获取线程任务函数的返回值。由于线程任务会在新线程中以异步方式执行,因此,线程执行的函数相当于一个“将来完成”的任务,所以
Python 使用 Future 来代表。

实际上,在 Java 的多线程编程中同样有
Future,此处的 Future 与 Java 的 Future 大同小异。

Future 提供了如下方法:

  • cancel():取消该 Future
    代表的线程任务。如果该任务正在执行,不可取消,则该方法返回
    False;否则,程序会取消该任务,并返回 True。

  • cancelled():返回 Future 代表的线程任务是否被成功取消。

  • running():如果该 Future 代表的线程任务正在执行、不可被取消,该方法返回
    True。

  • done():如果该 Funture 代表的线程任务被成功取消或执行完成,则该方法返回
    True。

  • result(timeout=None):获取该 Future 代表的线程任务最后返回的结果。如果
    Future 代表的线程任务还未完成,该方法将会阻塞当前线程,其中 timeout
    参数指定最多阻塞多少秒。

  • exception(timeout=None):获取该 Future
    代表的线程任务所引发的异常。如果该任务成功完成,没有异常,则该方法返回
    None。

  • add_done_callback(fn):为该 Future
    代表的线程任务注册一个“回调函数”,当该任务成功完成时,程序会自动触发该 fn
    函数。
    在用完一个线程池后,应该调用该线程池的 shutdown()
    方法,该方法将启动线程池的关闭序列。调用 shutdown()
    方法后的线程池不再接收新任务,但会将以前所有的已提交任务执行完成。当线程池中的所有任务都执行完成后,该线程池中的所有线程都会死亡。

    使用线程池来执行线程任务的步骤如下:

  1. 调用 ThreadPoolExecutor 类的构造器创建一个线程池。

  2. 定义一个普通函数作为线程任务。

  3. 调用 ThreadPoolExecutor 对象的 submit() 方法来提交线程任务。

  4. 当不想提交任何任务时,调用 ThreadPoolExecutor 对象的 shutdown()
    方法来关闭线程池。

Python网络编程

根据前面对网络分层棋型的介绍,我们知道实际的网络模型大致分为四层,这四层各有对应的网络协议提供支持,如图
1 所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0VCDCgUP-1614078116991)(media/305157811d9a6c42f528bf78adbe766e.gif)]
图 1 四层网络模型及对应的协议
网络层协议主要是 IP,它是所有互联网协议的基础,其中 ICMP(Internet Control
Message Protocol)、IGMP(Internet Group Manage Protocol)、ARP(Address
Resolution Protocol)、RARP(Reverse Address Resolution
Protocol)等协议都可认为是 IP
协议族的子协议。通常来说,很少会直接基于网络层进行应用程序编程。

传输层协议主要是 TCP 和 UDP,Python 提供了
socket 等模块针对传输层协议进行编程。
应用层协议就更多了,正如图 1 所示的,FTP、HTTP、TELNET
等协议都属于应用层协议,Python 同样为基于应用层协议的编程提供了丰富的支持。

虽然 Python
自带的标准库已经提供了很多与网络有关的模块,但如果在使用时觉得不够方便,则不要忘记了
Python 的优势,即大量的第三方模块随时可用于增强 Python 的功能。
表 2 显示了 Python 标准库中的网络相关模块。

表 2 Python 标准库中的网络相关模块
模块描述
socket基于传输层 TCP、UDP 协议进行网络编程的模块
asyncoresocket 模块的异步版,支持基于传输层协议的异步通信
asynchatasyncore 的增强版
cgi基本的 CGI(Common Gateway Interface,早期开发动态网站的技术)支持
emailE-mail 和 MLME 消息处理模块
ftplib支持 FTP 协议的客户端模块
httplib、http.client支持 HTTP 协议以及 HTTP 客户揣的模块
imaplib支持 IMAP4 协议的客户端模块
mailbox操作不同格式邮箱的模块
mailcap支持 Mailcap 文件处理的模块
nntplib支持 NTTP 协议的客户端模块
smtplib支持 SMTP 协议(发送邮件)的客户端模块
poplib支持 POP3 协议的客户端模块
telnetlib支持TELNET 协议的客户端模块
urllib及其子模块支持URL 处理的模块
xmlrpc、xmlrpc.server、xmlrpc.client支持XML-RPC协议的服务器端和客户端模块

经验案例

参考书目

Magnus《Python基础教程(第2版)》

Wesley《Python核心教程(第3版)》

Thomas《算法导论》

Micha《Python高性能编程》

Jon《编程珠玑(第2版)》

Robert《代码整洁之道》

参考资料

Python编程基础

Python编码工具

Sublime Text

Pycharm

VS Code0

测试部-云函数(基于VS Code)

阿里云-云开发平台(基于VS Code)

经验案例

参考书目

参考资料

Python源码剖析

Python源码剖析—编译Pyhton

Python对象初探(Python内建对象)

Python中的整数对象(Python内建对象)

Python中的字符对象(Python内建对象)

Python中的List对象(Python内建对象)

Python中的Dict对象(Python内建对象)

最简单的Python模拟—Small Python(Python内建对象)

Python的编译结果—Code对象与pyc文件(python虚拟机)

Python虚拟机框架(python虚拟机)

Python虚拟机中的一般表达式(python虚拟机)

Python虚拟机中的控制流(python虚拟机)

Python虚拟机中的函数机制(python虚拟机)

Python虚拟机中的类机制(python虚拟机)

Python运行环境初始化(python高级话题)

Python模块的动态加载机制(python高级话题)

Python多线程机制(python高级话题)

Python内存管理机制(python高级话题)

经验案例

参考书目

陈儒《Python源码剖析》

参考资料

    1.  

CPython源码

Python编码规范

行长度

每行不超过80个字符

以下情况除外:

  1. 长的导入模块语句

  2. 注释里的URL

不要使用反斜杠连接行。

Python会将 圆括号,
中括号和花括号中的行隐式的连接起来

, 你可以利用这个特点. 如果需要, 你可以在表达式外围增加一对额外的圆括号。

推荐: foo_bar(self, width, height, color=‘black’, design=None, x=‘foo’,

emphasis=None, highlight=0)

if (width == 0 and height == 0 and

color == ‘red’ and emphasis == ‘strong’):

如果一个文本字符串在一行放不下, 可以使用圆括号来实现隐式行连接:

x = ('这是一个非常长非常长非常长非常长 ’

‘非常长非常长非常长非常长非常长非常长的字符串’)

在注释中,如果必要,将长的URL放在一行上。

Yes: # See details at

#
http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html

No: # See details at

# http://www.example.com/us/developer/documentation/api/content/\

# v2.0/csv_file_name_extension_full_specification.html

注意上面例子中的元素缩进; 你可以在本文的 :ref:`缩进
<indentation>`部分找到解释.

括号

宁缺毋滥的使用括号

除非是用于实现行连接, 否则不要在返回语句或条件语句中使用括号.
不过在元组两边使用括号是可以的.

Yes: if foo:

bar()

while x:

x = bar() if x and y:

bar()

if not x:

bar()

return foo

for (x, y) in dict.items(): …

No: if (x):

bar()

if not(x):

bar()

return (foo)

缩进

用4个空格来缩进代码

绝对不要用tab, 也不要tab和空格混用. 对于行连接的情况,
你应该要么垂直对齐换行的元素(见 :ref:`行长度 <line_length>` 部分的示例),
或者使用4空格的悬挂式缩进(这时第一行不应该有参数):

Yes: # 与起始变量对齐

foo = long_function_name(var_one, var_two,

var_three, var_four)

# 字典中与起始值对齐

foo = {

long_dictionary_key: value1 +

value2,

}

# 4 个空格缩进,第一行不需要

foo = long_function_name(

var_one, var_two, var_three,

var_four)

# 字典中 4 个空格缩进

foo = {

long_dictionary_key:

long_dictionary_value,

}

No: # 第一行有空格是禁止的

foo = long_function_name(var_one, var_two,

var_three, var_four)

# 2 个空格是禁止的

foo = long_function_name(

var_one, var_two, var_three,

var_four)

# 字典中没有处理缩进

foo = {

long_dictionary_key:

long_dictionary_value,

}

注释

确保对模块, 函数, 方法和行内注释使用正确的风格

文档字符串

Python有一种独一无二的的注释方式: 使用文档字符串. 文档字符串是包, 模块,
类或函数里的第一个语句. 这些字符串可以通过对象的__doc__成员被自动提取,
并且被pydoc所用. (你可以在你的模块上运行pydoc试一把, 看看它长什么样).
我们对文档字符串的惯例是使用三重双引号"""(
PEP-257 ).
一个文档字符串应该这样组织: 首先是一行以句号,
问号或惊叹号结尾的概述(或者该文档字符串单纯只有一行). 接着是一个空行.
接着是文档字符串剩下的部分, 它应该与文档字符串的第一行的第一个引号对齐.
下面有更多文档字符串的格式化规范.

模块

每个文件应该包含一个许可样板. 根据项目使用的许可(例如, Apache 2.0, BSD, LGPL,
GPL), 选择合适的样板.

函数和方法

下文所指的函数,包括函数, 方法, 以及生成器.

一个函数必须要有文档字符串, 除非它满足以下条件:

外部不可见

非常短小

简单明了

文档字符串应该包含函数做什么, 以及输入和输出的详细描述. 通常,
不应该描述"怎么做", 除非是一些复杂的算法. 文档字符串应该提供足够的信息,
当别人编写代码调用该函数时, 他不需要看一行代码, 只要看文档字符串就可以了.
对于复杂的代码, 在代码旁边加注释会比使用文档字符串更有意义.

关于函数的几个方面应该在特定的小节中进行描述记录, 这几个方面如下文所述.
每节应该以一个标题行开始. 标题行以冒号结尾. 除标题行外,
节的其他内容应被缩进2个空格.

Args:

列出每个参数的名字, 并在名字后使用一个冒号和一个空格,
分隔对该参数的描述.如果描述太长超过了单行80字符,使用2或者4个空格的悬挂缩进(与文件其他部分保持一致).
描述应该包括所需的类型和含义. 如果一个函数接受*foo(可变长度参数列表)或者**bar
(任意关键字参数), 应该详细列出*foo和**bar.

Returns: (或者 Yields: 用于生成器)

描述返回值的类型和语义. 如果函数返回None, 这一部分可以省略.

Raises:

列出与接口有关的所有异常.

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):

“”"Fetches rows from a Bigtable.

Retrieves rows pertaining to the given keys from the Table instance

represented by big_table. Silly things may happen if

other_silly_variable is not None.

Args:

big_table: An open Bigtable Table instance.

keys: A sequence of strings representing the key of each table row

to fetch.

other_silly_variable: Another optional variable, that has a much

longer name than the other args, and which does nothing.

Returns:

A dict mapping keys to the corresponding table row data

fetched. Each row is represented as a tuple of strings. For

example:

{‘Serak’: (‘Rigel VII’, ‘Preparer’),

‘Zim’: (‘Irk’, ‘Invader’),

‘Lrrr’: (‘Omicron Persei 8’, ‘Emperor’)}

If a key from the keys argument is missing from the dictionary,

then that row was not found in the table.

Raises:

IOError: An error occurred accessing the bigtable.Table object.

“”"

pass

类应该在其定义下有一个用于描述该类的文档字符串.
如果你的类有公共属性(Attributes), 那么文档中应该有一个属性(Attributes)段.
并且应该遵守和函数参数相同的格式.

class SampleClass(object):

“”"Summary of class here.

Longer class information…

Longer class information…

Attributes:

likes_spam: A boolean indicating if we like SPAM or not.

eggs: An integer count of the eggs we have laid.

“”"

def _init_(self, likes_spam=False):

“”“Inits SampleClass with blah.”""

self.likes_spam = likes_spam

self.eggs = 0

def public_method(self):

“”“Performs operation blah.”""

块注释和行注释

最需要写注释的是代码中那些技巧性的部分. 如果你在下次
代码审查 的时候必须解释一下,
那么你应该现在就给它写注释. 对于复杂的操作, 应该在其操作开始前写上若干行注释.
对于不是一目了然的代码, 应在其行尾添加注释.

# We use a weighted dictionary search to find out where i is in

# the array. We extrapolate position based on the largest num

# in the array and the array size and then do binary search to

# get the exact number.

if i & (i-1) == 0: # true iff i is a power of 2

为了提高可读性, 注释应该至少离开代码2个空格.

另一方面, 绝不要描述代码. 假设阅读代码的人比你更懂Python,
他只是不知道你的代码要做什么.

# BAD COMMENT: Now go through the b array and make sure whenever i occurs

# the next element is i+1

如果一个类不继承自其它类, 就显式的从object继承. 嵌套类也一样.

Yes: class SampleClass(object):

pass

class OuterClass(object):

class InnerClass(object):

pass

class ChildClass(ParentClass):

“”“Explicitly inherits from another class already.”""

No: class SampleClass:

pass

class OuterClass:

class InnerClass:

pass

继承自 object 是为了使属性(properties)正常工作, 并且这样可以保护你的代码,
使其不受Python 3000的一个特殊的潜在不兼容性影响. 这样做也定义了一些特殊的方法,
这些方法实现了对象的默认语义, 包括 _new_, _init_, _delattr_,
_getattribute_, _setattr_, _hash_, _repr_, and _str_ .

TODO注释

为临时代码使用TODO注释, 它是一种短期解决方案. 不算完美, 但够好了.

TODO注释应该在所有开头处包含"TODO"字符串, 紧跟着是用括号括起来的你的名字,
email地址或其它标识符. 然后是一个可选的冒号. 接着必须有一行注释, 解释要做什么.
主要目的是为了有一个统一的TODO格式,
这样添加注释的人就可以搜索到(并可以按需提供更多细节).
写了TODO注释并不保证写的人会亲自解决问题. 当你写了一个TODO, 请注上你的名字.

# TODO(kl@gmail.com): Use a “*” here for string repetition.

# TODO(Zeke) Change this to use relations.

如果你的TODO是"将来做某事"的形式,
那么请确保你包含了一个指定的日期(“2009年11月解决”)或者一个特定的事件(“等到所有的客户都可以处理XML请求就移除这些代码”).

命名

module_name, package_name, ClassName, method_name, ExceptionName, function_name,
GLOBAL_VAR_NAME, instance_var_name, function_parameter_name, local_var_name.

应该避免的名称

  1. 单字符名称, 除了计数器和迭代器.

  2. 包/模块名中的连字符(-)

  3. 双下划线开头并结尾的名称(Python保留, 例如_init_)

命名约定

  1. 所谓"内部(Internal)"表示仅模块内可用, 或者, 在类内是保护或私有的.

  2. 用单下划线(_)开头表示模块变量或函数是protected的(使用import *
    from时不会包含).

  3. 用双下划线(__)开头的实例变量或方法表示类内私有.

  4. 将相关的类和顶级函数放在同一个模块里. 不像Java, 没必要限制一个类一个模块.

  5. 对类名使用大写字母开头的单词(如CapWords, 即Pascal风格),
    但是模块名应该用小写加下划线的方式(如lower_with_under.py).
    尽管已经有很多现存的模块使用类似于CapWords.py这样的命名,
    但现在已经不鼓励这样做, 因为如果模块名碰巧和类名一致, 这会让人困扰.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iYwPQOIM-1614078116992)(media/7b8da3ca1bbe2762eb6f116bb458eff3.png)]

Main

即使是一个打算被用作脚本的文件, 也应该是可导入的.
并且简单的导入不应该导致这个脚本的主功能(main functionality)被执行,
这是一种副作用. 主功能应该放在一个main()函数中.

在Python中, pydoc以及单元测试要求模块必须是可导入的.
你的代码应该在执行主程序前总是检查 if _name_ == ‘main’ ,
这样当模块被导入时主程序就不会被执行.

def main():

if _name_ == ‘main’:

main()

所有的顶级代码在模块导入时都会被执行. 要小心不要去调用函数, 创建对象,
或者执行那些不应该在使用pydoc时执行的操作.

经验案例

参考书目

参考资料

PEP 8 – Style Guide for Python Code

Python 编码规范(Google)

软件建模与设计

UML类图

1. 泛化(Generalization)

【泛化关系】:是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为。

例如:老虎是动物的一种,即有老虎的特性也有动物的共性。

【箭头指向】:带三角箭头的实线,箭头指向父类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-89mxIZPV-1614078116992)(media/24b53fd9d9b38eed8fb41d637461cb3f.png)]

2. 实现(Realization)

【实现关系】:是一种类与接口的关系,表示类是接口所有特征和行为的实现.

【箭头指向】:带三角箭头的虚线,箭头指向接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iUSoXXhl-1614078116993)(media/d7804708323a61859c602ee70f661abb.png)]

3. 关联(Association)

【关联关系】:是一种拥有的关系,它使一个类知道另一个类的属性和方法;如:老师与学生,

丈夫与妻子关联可以是双向的,也可以是单向的。

双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。

【代码体现】:成员变量

【箭头及指向】:带普通箭头的实心线,指向被拥有者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-89TP2s4a-1614078116993)(media/8641d79c9e2070e8ed0e38cd8958fb74.png)]

上图中,老师与学生是双向关联,老师有多名学生,学生也可能有多名老师。

但学生与某课程间的关系为单向关联,一名学生可能要上多门课程,课程是个抽象的东西他不拥有学生。

下图为自身关联:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r9OgeOun-1614078116993)(media/24df7a5e00e7545786cc6bae127f4d29.png)]

4. 聚合(Aggregation)

【聚合关系】:是整体与部分的关系,且部分可以离开整体而单独存在。

如车和轮胎是整体和部分的关系,轮胎离开车仍然可以存在。

聚合关系是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。

【代码体现】:成员变量

【箭头及指向】:带空心菱形的实心线,菱形指向整体

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HcWcsWjh-1614078116994)(media/a66145d66c34c67ad172e4b8c28e2139.png)]

5. 组合(Composition)

【组合关系】:是整体与部分的关系,但部分不能离开整体而单独存在。

如公司和部门是整体和部分的关系,没有公司就不存在部门。

组合关系是关联关系的一种,是比聚合关系还要强的关系,

它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期。

【代码体现】:成员变量

【箭头及指向】:带实心菱形的实线,菱形指向整体

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HMiaBRVz-1614078116994)(media/a9005d9c756c4f1ea1db8e627c6ff9f2.png)]

6. 依赖(Dependency)

【依赖关系】:是一种使用的关系,即一个类的实现需要另一个类的协助,

所以要尽量不使用双向的互相依赖.

【代码表现】:局部变量、方法的参数或者对静态方法的调用

【箭头及指向】:带箭头的虚线,指向被使用者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kMy0V8bG-1614078116995)(media/43f13ae8abc1749dd8c4a64a15d8f374.png)]

7.类图集合关系

各种关系的强弱顺序:

泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

下面这张UML图,比较形象地展示了各种类图关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-12zeJD16-1614078116995)(media/36a85b46d203432f1d777402e1ae8109.png)]

类图绘制的要点

1类的操作是针对类自身的操作,而不是它去操作人家。比如书这个类有上架下架的操作,是书自己被上架下架,不能因为上架下架是管理员的动作而把它放在管理员的操作里。

2两个相关联的类,需要在关联的类中加上被关联类的ID,并且箭头指向被关联类。可以理解为数据表中的外键。比如借书和书,借书需要用到书的信息,因此借书类需包含书的ID,箭头指向书。

3由于业务复杂性,一个显示中的实体可能会被分为多个类,这是很正常的,类不是越少越好。类的设计取决于怎样让后台程序的操作更加简单。比如单看逻辑,借书类可以不存在,它的信息可以放在书这个类里。然而借还书和书的上架下架完全不是一回事,借书类对借书的操作更加方便,不需要去重复改动书这个类中的内容。此外,如果书和借书是1对多的关系,那就必须分为两个类。

4类图中的规范问题,比如不同关系需要不同的箭头,可见性符号等。

UML时序图

时序图(Sequence
Diagram)是显示对象之间交互的图,这些对象是按时间顺序排列的。顺序图中显示的是参与交互的对象及其对象之间消息交互的顺序。时序图中包括的建模元素主要有:角色(Actor)、对象(Actor)、生命线(Lifeline)、控制焦点(Activation)、消息(Message)、自关联消息、组合片段。

角色

系统角色,可以是人、及其甚至其他的系统或者子系统。

对象

对象包括三种命名方式:

第一种方式包括对象名和类名;

第二中方式只显示类名不显示对象名,即表示他是一个匿名对象;

第三种方式只显示对象名不显示类名。

生命线

生命线在顺序图中表示为从对象图标向下延伸的一条虚线,表示对象存在的时间。

控制焦点

控制焦点是顺序图中表示时间段的符号,在这个时间段内对象将执行相应的操作。用小矩形表示。

消息

消息一般分为同步消息(Synchronous Message),异步消息(Asynchronous
Message)和返回消息(Return Message)。

同步消息:消息的发送者把控制传递给消息的接收者,然后停止活动,等待消息的接收者放弃或者返回控制。用来表示同步的意义。

异步消息:消息发送者通过消息把信号传递给消息的接收者,然后继续自己的活动,不等待接受者返回消息或者控制。异步消息的接收者和发送者是并发工作的。

返回消息:返回消息表示从过程调用返回。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8EfPnJea-1614078116995)(media/c88b4fb23da07dbc0db088a22462d51c.png)]

自关联消息

表示方法的自身调用或者一个对象内的一个方法调用另外一个方法。以一个半闭合的长方形+下方实心剪头表示。

UML时序图组合片段简要说明 :

ref:引用其他地方定义的组合片段;
alt:在一组行为中根据特定的条件选择某个交互;
opt:表示一个可选的行为;
break:提供了和编程语言中的break类拟的机制;
par:支持交互片段的并发执行;
seq:强迫交互按照特定的顺序执行;
strict:明确定义了一组交互片段的执行顺序;
neg:用来标志不应该发生的交互;
region:标志在组合片段中先于其他交互片断发生的交互;
ignore:明确定义了交互片段不应该响应的消息;
consider:明确标志了应该被处理的消息
assert:标志了在交互片段中作为事件唯一的合法继续者的操作数;
loop:说明交互片段会被重复执行

例如:并行:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jC5u6yBW-1614078116996)(media/28a1b9fe31872852ec5d491e3779afac.png)]

例如:循环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eP5KaWx1-1614078116996)(media/1b96d660ae7148d870a6e28f3fa8657f.png)]

Stay hungry,stay foolish !

经验案例

参考书目

Hassan《软件建模与设计》

George《分布式系统 概念与设计》

Martin《架构即未来》

Martin《架构真经》

Martin《企业IT架构转型之道》

Richard《面向对象程序设计》

Brendan《分布式系统设计》

参考资料

设计模式

概览

二十三种设计模式及其python实现

本文源码寄方于github:https://github.com/w392807287/Design_pattern_of_python

参考文献:

《大话设计模式》——吴强

《Python设计模式》——pythontip.com

《23种设计模式》——http://www.cnblogs.com/beijiguangyong/

设计模式是什么?

设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码。反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。

起初,你会认为“模式”就是为了解决一类特定问题而特别想出来的明智之举。说的没错,看起来的确是通过很多人一起工作,从不同的角度看待问题进而形成的一个最通用、最灵活的解决方案。也许这些问题你曾经见过或是曾经解决过,但是你的解决方案很可能没有模式这么完备。

虽然被称为“设计模式”,但是它们同“设计“领域并非紧密联系。设计模式同传统意义上的分析、设计与实现不同,事实上设计模式将一个完整的理念根植于程序中,所以它可能出现在分析阶段或是更高层的设计阶段。很有趣的是因为设计模式的具体体现是程序代码,因此可能会让你认为它不会在具体实现阶段之前出现(事实上在进入具体实现阶段之前你都没有意识到正在使用具体的设计模式)。

可以通过程序设计的基本概念来理解模式:增加一个抽象层。抽象一个事物就是隔离任何具体细节,这么做的目的是为了将那些不变的核心部分从其他细节中分离出来。当你发现你程序中的某些部分经常因为某些原因改动,而你不想让这些改动的部分引发其他部分的改动,这时候你就需要思考那些不会变动的设计方法了。这么做不仅会使代码可维护性更高,而且会让代码更易于理解,从而降低开发成本。

这里列举了三种最基本的设计模式:

  1. 创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。

  2. 结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。

  3. 行为模式,用于在不同的实体建进行通信,为实体之间的通信提供更容易,更灵活的通信方法。

创建型

1. Factory Method(工厂方法)

2. Abstract Factory(抽象工厂)

3. Builder(建造者)

4. Prototype(原型)

5. Singleton(单例)

结构型

6. Adapter Class/Object(适配器)

7. Bridge(桥接)

8. Composite(组合)

9. Decorator(装饰)

10. Facade(外观)

11. Flyweight(享元)

12. Proxy(代理)

行为型

13. Interpreter(解释器)

14. Template Method(模板方法)

15. Chain of Responsibility(责任链)

16. Command(命令)

17. Iterator(迭代器)

18. Mediator(中介者)

19. Memento(备忘录)

20. Observer(观察者)

21. State(状态)

22. Strategy(策略)

23. Visitor(访问者)

创建型

Factory Method(工厂方法)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-22B9cWMG-1614078116997)(media/9c24b61f8790080520b714851c18cf09.png)]

意图:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method
使个类的实例化延迟到其子类。

适用性:

当一个类不知道它所必须创建的对象的类的时候。

当一个类希望由它的子类来指定它所创建的对象的时候。

当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

实现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NeWWTQFi-1614078116997)(media/2887ee03dee8a48be631710050f6367f.png)]

Abstract Factory(抽象工厂)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QsfMlrQF-1614078116997)(media/bb8122cf7233a0f712a3b45da626229f.png)]

意图:

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
适用性:

一个系统要独立于它的产品的创建、组合和表示时。

一个系统要由多个产品系列中的一个来配置时。

当你要强调一系列相关的产品对象的设计以便进行联合使用时。

当你提供一个产品类库,而只想显示它们的接口而不是实现时。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CHbipdFx-1614078116998)(media/9d8b46e114517f0299692cb973498ee4.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SqRO29wr-1614078116998)(media/7d73434936079b13c3b7fd047909101d.png)]

Builder(建造者)

意图:

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

适用性:

当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

当构造过程必须允许被构造的对象有不同的表示时。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NJrU00wm-1614078116999)(media/46789de5bee85eb8f1098535e7f7dc2b.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VLQzLn8N-1614078116999)(media/79e8521c66d537338b63b780afa023bf.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qHEvke9B-1614078117000)(media/976fccf41b97291bf35700efe26de85a.png)]

Singleton(单例)

意图:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用性:

当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yBrTVVCH-1614078117000)(media/10a7c4d6cb76de4f9650c13561414735.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q32VBRD1-1614078117001)(media/26b95070f24bc5c1fcc141a9a1e8b4ef.png)]

结构型

Proxy(代理)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ifsIWIyX-1614078117001)(media/c229392d9e02518a42c15d284dad99f5.png)]

意图:

为其他对象提供一种代理以控制对这个对象的访问。

适用性:

在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式。下面是一
些可以使用Proxy 模式常见情况:

  1. 远程代理(Remote Proxy )为一个对象在不同的地址空间提供局部代表。
    NEXTSTEP[Add94] 使用NXProxy 类实现了这一目的。Coplien[Cop92] 称这种代理为“大使”
    (Ambassador )。
    2 )虚代理(Virtual Proxy
    )根据需要创建开销很大的对象。在动机一节描述的ImageProxy
    就是这样一种代理的例子。
  2. 保护代理(Protection Proxy )控制对原始对象的访问。保护代理用于对象应该有不同
    的访问权限的时候。例如,在Choices 操作系统[
    CIRM93]中KemelProxies为操作系统对象提供 了访问保护。
    4 )智能指引(Smart Reference
    )取代了简单的指针,它在访问对象时执行一些附加操作。
    它的典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它(也称为SmartPointers[Ede92
    ] )。

当第一次引用一个持久对象时,将它装入内存。在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

行为型

Template Method模板方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-87856qFa-1614078117002)(media/3f58ecc598978c520120b03809a84d72.png)]

意图:

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod
使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

适用性:

一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是Opdyke
和Johnson所描述过的“重分解以一般化”的一个很好的例子[ OJ93
]。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

控制子类扩展。模板方法只在特定点调用“hook
”操作(参见效果一节),这样就只允许在这些点进行扩展。

Command(命令)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fRTXeJXV-1614078117002)(media/17b7591caf553a17b79cd2126db18a9b.jpeg)]

意图:

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

适用性:

抽象出待执行的动作以参数化某对象,你可用过程语言中的回调(call
back)函数表达这种参数化机制。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。Command
模式是回调机制的一个面向对象的替代品。

在不同的时刻指定、排列和执行请求。一个Command对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。

支持取消操作。Command的Excute
操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command
接口必须添加一个Unexecute操作,该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消”和“重做”。

支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。在Command接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute操作重新执行它们。

用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务(
transaction)的信息系统中很常见。一个事务封装了对数据的一组变动。Command模式提供了对事务进行建模的方法。Command有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。

经验案例

参考书目

Erich《设计模式》

程杰《大话设计模式》

参考资料

代码重构

引言

我该怎么开始介绍重构(refactoring)呢?按照传统作法,一开始介绍某个东西时,首先应该大致讲讲它的历史、主要原理等等。可是每当有人在会场上介绍这些东西,总是诱发我的瞌睡虫。我的思绪开始游荡,我的眼神开始迷离,直到他或她拿出实例,我才能够提起精神。实例之所以可以拯救我于太虚之中,因为它让我看见事情的真正行进。谈厚理,很容易流于泛泛,又很难说明如何实际应用。给出一个实例,
却可以帮助我把事情认识清楚。

所以我决定以一个实例作为本书起点。在此过程中我将告诉你很多重构原理,并且让你对重构过程有一点感觉。然后我才能向你提供普通惯见的原理介绍。

但是,面对这个介绍性实例,我遇到了一个大问题。如果我选择一个大型程序,对程序自身的描述和对重构过程的描述就太复杂了,任何读者都将无法掌握(我试了
一下,哪怕稍微复杂一点的例子都会超过100页)。如果我选择一个够小以至于容易理解的程序,又恐怕看不出重构的价值。

和任何想要介绍「应用于真实世界中的有用技术」的人一样,我陷入了一个十分典型的两难困境。我将带引你看看如何在一个我所选择的小程序中进行重构,然而坦白说,那个程序的规模根本不值得我们那么做。但是如果我给你看的代码是大系统的一部分,重构技术很快就变得重要起来。所以请你一边观赏这个小例子,一边想像它身处于一个大得多的系统。

为何重构

我不想把重构说成治百病的万灵丹,它绝对不是所谓的「银弹」[1]。不过它的确很有价值,虽不是一颗银子弹却是一把「银钳子」,可以帮助你始终良好地控制自己的代码。重构是个工具,它可以(并且应该)为了以下数个目的而被运用。

[1]译注:「银弹」(silver bullet)是美国家喻户晓的比喻。美国民间流传月圆之夜狼人
出没,只有以纯银子弹射穿狼人心脏,才能制服狼人。

「重构」改进软件设计

如果没有重构,程序的设计会逐渐腐败变质。当人们只为短期目的,或是在完全理解整体设计之前,就贸然修改代码,程序将逐渐失去自己的结构,程序员愈来愈难通过阅读源码而理解原本设计。重构很像是在整理代码,你所做的就是让所有东西回到应该的位置上。代码结构的流失是累积性的。愈难看出代码所代表的设计意涵,就愈难保护其中设计,于是该设计就腐败得愈快。经常性的重构可以帮助代码维持自己该有的形态。

同样完成一件事,设计不良的程序往往需要更多代码,这常常是因为代码在不同的地方使用完全相同的语句做同样的事。因此改进设计的一个重要方向就是消除重复代码(Duplicate
Code)。这个动作的重要性着眼于未来。代码数量减少并不会使系统运行更快,因为这对程序的运行轨迹几乎没有任何明显影响。然而代码数量减少将使未来可能的程序修改动作容易得多。代码愈多,正确的修改就愈困难,因为有更多代码需要理解。你在这儿做了点修改,系统却不如预期那样工作,因为你未曾修改另一处——那儿的代码做着几乎完全一样的事情,只是所处环境略有不同。
如果消除重复代码,你就可以确定代码将所有事物和行为都只表述一次,惟一一次,这正是优秀设计的根本。

「重构」使软件更易被理解

从许多角度来说,所谓程序设计,便是与计算机交谈。你编写代码告诉计算机做什么事,它的响应则是精确按照你的指示行动。你得及时填补「想要它做什么」和「告
诉它做什么」之间的缝隙。这种编程模式的核心就是「准确说出吾人所欲」。除了计算机外,你的源码还有其他读者:数个月之后可能会有另一位程序员尝试读懂你的代码并做一些修改。我们很容易忘记这第二位读者,但他才是最重要的。计算机是否多花了数个钟头进行编译,又有什么关系呢?如果一个程序员花费一周时间来修改某段代码,那才关系重大——如果他理解你的代码,这个修改原本只需一小时。

问题在于,当你努力让程序运转的时候,你不会想到未来出现的那个开发者。是的,是应该改变一下我们的开发节奏,对代码做适当修改,让代码变得更易理解。重构可以帮助我们让代码更易读。一开始进行重构时,你的代码可以正常运行,但结构不够理想。在重构上花一点点时间,就可以让代码更好地表达自己的用途。这种编程模式的核心就是「准确说出你的意思」。

关于这一点,我没必要表现得如此无私。很多时候那个「未来的开发者」就是我自己。此时重构就显得尤其重要了。我是个很懒惰的程序员,我的懒惰表现形式之一就是:总是记不住自己写过的代码。事实上对于任何立可查阅的东西我都故意不去记它,因为我怕把自己的脑袋塞爆。我总是尽量把该记住的东西写进程序里头,这样我就不必记住它了。这么一来我就不必太担心Old
Peculier(译注:一种有名的麦芽酒〉[Jackson]杀光我的脑细胞。

这种可理解性还有另一方面的作用。我利用重构来协助我理解不熟悉的代码。当我看到不熟悉的代码,我必须试着理解其用途。我先看两行代码,然后对自己说:『噢,
是的,它做了这些那些……』。有了重构这个强大武器在手,我不会满足于这么一点脑中体会。我会真正动手修改代码,让它更好地反映出我的理解,然后重新执行,看它是否仍然正常运作,以此检验我的理解是否正确。

一开始我所做的重构都像这样停留在细枝末节上。随着代码渐趋简洁,我发现自己可以看到一些以前看不到的设计层面的东西。如果不对代码做这些修改,也许我永远看不见它们,因为我的聪明才智不足以在脑子里把这一切都想像出来。Ralph
Johnson把这种「早期重构」描述为「擦掉窗户上的污垢,使你看得更远」。研究代码时我发现,重构把我带到更高的理解层次上。如果没有重构,我达不到这种层次。

代码的坏味道

现在,对于「重构如何运作」,你已经有了相当好的理解。但是知道How不代表
知道When。决定何时重构、何时停止和知道重构机制如何运转是一样重要的。

难题来了!解释「如何删除一个instance变量」或「如何产生一个class
hierarchy(阶层体系)」很容易,因为这些都是很简单的事情。但要解释「该在什么时候做这些动作」就没那么顺理成章了。除了露几手含混的编程美学(说实话,这就是咱
这些顾问常做的事),我还希望让某些东西更具说服力一些。

去苏黎士拜访Kent
Beck的时候,我正在为这个微妙的问题大伤脑筋。也许是因为受到刚出生的女儿的气味影响吧,他提出「用味道来形容重构时机」。『味道』,他说,『听起来是不是比含混的美学理论要好多了?』啊,是的。我们看过很多很
多代码,它们所属的项目从大获成功到奄奄一息都有。观察这些代码时,我们学会了从中找寻某些特定结构,这些结构指出(有时甚至就像尖叫呼喊)重构的可能性。(本章主词换成「我们」,是为了反映一个事实:Kent和我共同撰写本章。你应该可以看出我俩的文笔差异——插科打诨的部分是我写的,其余都是他的。〕

我们并不试图给你一个「重构为时晚矣」的精确衡量标准。从我们的经验看来,没有任何量度规矩比得上一个见识广博者的直觉。我们只会告诉你一些迹象,它会指出「这里有一个可使用重构解决的问题」。你必须培养出自己的判断力,学会判断一个class内有多少instance变量算是太大、一个函数内有多少行代码才算太长。

如果你无法确定该进行哪一种重构手法,请阅读本章内容和封底内页表格来寻找灵感。你可以阅读本章(或快速浏览封底内页表格〕来判断自己闻到的是什么味道,
然后再看看我们所建议的重构手法能否帮助你。也许这里所列的「臭味条款」和你所检测的不尽相符,但愿它们能够为你指引正确方向。

构筑测试体系

如果你想进行重构(refactoring),首要前提就是拥有一个可靠的测试环境。就算你够幸运,有一个可以自动进行重构的工具,你还是需要测试。而且短时间内不可能有任何工具可以为我们自动进行所有可能的重构。

我并不把这视为缺点。我发现,编写优良的测试程序,可以极大提高我的编程速度,即使不进行重构也一样如此。这让我很吃惊,也违反许多程序员的直觉,所以我有
必要解释一下这个现象。

经验案例

参考书目

阿瑟诺维斯基《代码重构》

参考资料

操作系统

经验案例

参考书目

鸟哥《Linux 私房菜》

Randal《深入理解计算机系统》

Neil《Linux程序设计》

Alfred《编译原理》

参考资料

网络安全

经验案例

参考书目

参考资料

网络体系

经验案例

参考书目

David《HTTP 权威指南》

参考资料

数据库

SQL数据库原生

SQL (Structured Query Language)
是具有数据操纵和数据定义等多种功能的数据库语言,这种语言具有交互性特点,能为用户提供极大的便利,数据库管理系统应充分利用SQL语言提高计算机应用系统的工作质量与效率。SQL语言不仅能独立应用于终端,还可以作为子语言为其他程序设计提供有效助力,该程序应用中,SQL可与其他程序语言一起优化程序功能,进而为用户提供更多更全面的信息。具体的实现包括MySQL、SQLite等。

MySQL

MySQL是一个关系型数据库管理系统,由瑞典MySQL
AB 公司开发,属于 Oracle 旗下产品。MySQL
是最流行的关系型数据库管理系统之一,在
WEB 应用方面,MySQL是最好的 RDBMS
(Relational Database Management System,关系数据库管理系统) 应用软件之一。

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。

MySQL所使用的 SQL
语言是用于访问数据库的最常用标准化语言。MySQL
软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择
MySQL 作为网站数据库。

SQLite

SQLite - 概述:

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如
Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。
至2019年已经有19个年头,SQLite也迎来了一个版本 SQLite 3已经发布。

ORM

Python目前比较流行的ORM框架主要是SQLAlchemy框架,它可以兼容MySQL、SQLite、Oracle等多种关系型数据库。

SQLAlchemy

SQLAlchemy - 概述:

SQLAlchemy
SQL工具包和对象关系映射器是一套用于处理数据库和Python的综合工具。它有几个不同的功能领域,可以单独使用或组合在一起。其主要组件如下所示,组件依赖关系组织成层:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gJGtMTcs-1614078117003)(media/aa8788f050a062cdd58dbed6e133a4dd.png)]

以上,SQLAlchemy的两个最重要的前向部分是 对象关系映射器 以及
SQL表达式语言。SQL表达式可以独立于ORM使用。使用ORM时,SQL表达式语言仍然是面向公共的API的一部分,因为它在对象关系配置和查询中使用。如果对于SQLAlchemy有更加全面的了解,建议查看附录文档。

对象存储服务

MinIO

内存存储服务

Redis

经验案例

视频会议系统的状态监控服务 – 通信模块&数据库读写模块部分经验案例

SQLAlchemy–Python下的ORM工具使用经验案例

参考书目

Abrahan《数据库系统概念》

Schwartz《高性能MySQL》

参考资料

web框架

Django

你所需要知道的关于 Django 的一切。

这份文档是如何组织的

Django 有丰富的文档。一份高度概述的文档会告诉你在哪里找到特定的东西:

教程
通过手把手地方式教你一步步的创建一个 Web 应用。如果你初学 Django
或编程,请从这里开始。也请看看下面的
快速入门”。

专题指南
在相当高的层次上介绍关键主题和概念,并提供有用的背景信息和解释。

参考指南 包含 API 和 Django
各个工作机制方面的技术参考。它们介绍了 Django
是如何工作,如何被使用的。不过,你得先对关键字的概念有一定理解。

How-to 指南
是目录。它们以排列好的关键问题和用例的方式指导你。它们比教程更加深入,且需要你先了解一些关于
Django 是如何工作的知识。

快速入门

您是刚学 Django 或是初学编程? 这就是你开始学习的地方!

从零开始: 概要 |
安装

入门教程: 第1节:
请求和响应
|
第2节: 模型和 admin
站点
| 第3节:
视图和模板
|
第4节:
表单和通用视图
|
第5节: 测试 |
第6节: 静态文件
| 第7节: 自定义 admin
站点

进阶教程 :
如何编写可复用的应用
| 提交你的第一个 Django
补丁

Flask

经验案例

参考书目

参考资料

运维模型

SRE google运维

管理kubernetes(k8s)

Docker

经验案例

参考书目

Brendan《管理Kubernetes》

Sean《Docker即学即用》

Betsy《SRE Google运维解密》

参考资料

机器学习理论资料

规则方法

统计方法

经验案例

参考书目

Ian《Deep Learning》

Richard《现代控制系统(第12版)》

Peter《机器学习实战》

美团算法团队《美团机器学习实践》

李航《统计学习方法》

参考资料

机器学习框架

tensorflow

简介

本章的目的是让你了解和运行 TensorFlow!

在开始之前, 让我们先看一段使用 Python API 撰写的 TensorFlow 示例代码,
让你对将要学习的内容有初步的印象.

这段很短的 Python 程序生成了一些三维数据, 然后用一个平面拟合它.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FrMxJ9mL-1614078117003)(media/3f4ef1844d9a41fe52aa9c5c5ac1ecc7.png)]

为了进一步激发你的学习欲望, 我们想让你先看一下 TensorFlow
是如何解决一个经典的机器 学习问题的. 在神

经网络领域, 最为经典的问题莫过于 MNIST 手写数字分类问题. 我们准备了
两篇不同的教程, 分别面向机器学

习领域的初学者和专家. 如果你已经使用其它软件训练过许多 MNIST 模型,
请阅读高级教程 (红色药丸链接).

第 1 章 起步 | 9

如果你以前从未听说过 MNIST, 请阅读初级教程 (蓝色药丸链接).
如果你的水平介于这两类人之间, 我们建议你

先快速浏览初级教程, 然后再阅读高级教程.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NXd2TCU4-1614078117003)(media/631f4b5b454aa165c57a643f92bf4104.emf)]

图片 1.1 面向机器学习初学者的 MNIST 初级教程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OAsqk2qP-1614078117004)(media/7de2e5fddac15ade64273587f7db630e.emf)]

图片 1.2 面向机器学习专家的 MNIST 高级教程

图片由 CC BY-SA 4.0 授权; 原作者 W. Carter

如果你已经下定决心, 准备学习和安装 TensorFlow, 你可以略过这些文字, 直接阅读
后面的章节. 不用担心,

你仍然会看到 MNIST – 在阐述 TensorFlow 的特性时, 我们还会使用 MNIST
作为一个样例.

MNIST机器学习入门

这个教程的目标读者是对机器学习和TensorFlow都不太了解的新手。如果你已经了解MNIST和softmax回归(softma
x regression)的相关知识,你可以阅读这个快速上手教程。

当我们开始学习编程的时候,第一件事往往是学习打印"Hello
World"。就好比编程入门有Hello
World,机器学习入门有MNIST。MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片:它也包含每一张图片对应的标签,告诉我们这个是数字几。比如,上面这四张图片的标签分别是5,0,4,1。在此教程中,我们将训练一个机器学习模型用于预测图片里面的数字。我们的目的不是要设计一个世界一流的复杂模型
– 尽管我们会在之后给你源代码去实现一流的预测模型 –
而是要介绍下如何使用TensorFlow。所以,我们这里会从一个很简单的数学模型开始,它叫Softmax
Regression。对应这个教程的实现代码很短,而且真正有意思的内容只包含在三行代码里面。但是,去理解包含在这些代码里面的设计思想是非常重要的:TensorFlow工作流程和机器学习的基本概念。因此,这个教程会很详细地介绍这些代码的实现原理。

MNIST数据集

MNIST数据集的官网是Yann LeCun’s
website。在这里,我们提供了一份python源代码用于自动下载和安装这个数据集。你可以下载这份代码,然后用下面的代码导入到你的项目里面,也可以直接复制粘贴到你的代码文件里面。

import input_data

mnist = input_data.read_data_sets(“MNIST_data/”, one_hot=True)

下载下来的数据集被分成两部分:60000行的训练数据集( mnist.train
)和10000行的测试数据集( mnist.test
)。这样的切分很重要,在机器学习模型设计时必须有一个单独的测试数据集不用于训练而是用来评估这个模

型的性能,从而更加容易把设计的模型推广到其他数据集上(泛化)。

正如前面提到的一样,每一个MNIST数据单元有两部分组成:一张包含手写数字的图片和一个对应的标签。我们把这些图片设为“xs”,把这些标签设为“ys”。训练数据集和测试数据集都包含xs和ys,比如训练数据集的图片是mnist.train.images
,训练数据集的标签是mnist.train.labels
。每一张图片包含28X28个像素点。我们可以用一个数字数组来表示这张图片:我们把这个数组展开成一个向量,长度是
28x28 =
784。如何展开这个数组(数字间的顺序)不重要,只要保持各个图片采用相同的方式展开。从这个角度来看,MNIST数据集的图片就是在784维向量空间里面的点,
并且拥有比较复___________杂的结构(提醒:
此类数据的可视化是计算密集型的)。展平图片的数字数组会丢失图片的二维结构信息。这显然是不理想的,最优秀的计算机视觉方法会挖掘并利用这些结构信息,我们会在后续教程中介绍。但是在这个教程中我们忽略这些结构,所介绍的简单数学模型,softmax回归(softmax
regression),不会利用这些结构信息。因此,在MNIST训练数据集中,
mnist.train.images 是一个形状为[60000, 784]
的张量,第一个维度数字用来索引图片,第二个维度数字用来索引每张图片中的像素点。在此张量里的每一个元素,都表示某张图片里的某个像素的强度值,值介于0和1之间。

相对应的MNIST数据集的标签是介于0到9的数字,用来描述给定图片里表示的数字。为了用于这个教程,我们使标签数据是"one-hot
vectors"。
一个one-hot向量除了某一位的数字是1以外其余各维度数字都是0。所以在此教程中,数字n将表示成一个只有在第n维度(从0开始)数字为1的10维向量。比如,标签0将表示成([1,0,0,0,0,0,0,0,0,0,0])。因此,
mnist.train.labels 是一个[60000, 10]
的数字矩阵。现在,我们准备好可以开始构建我们的模型啦!

Softmax回归介绍

我们知道MNIST的每一张图片都表示一个数字,从0到9。我们希望得到给定图片代表每个数字的概率。比如说,我们的模型可能推测一张包含9的图片代表数字9的概率是80%但是判断它是8的概率是5%(因为8和9都有上半部分的小圆),然后给予它代表其他数字的概率更小的值。这是一个使用softmax回归(softmax
regression)模型的经典案例。softmax模型可以用来给不同的对象分配概率。即使在之后,我们训练更加精细的模型时,最后一步也需要softmax来分配概率。softmax回归(softmax
regression)分两步:第一步为了得到一张给定图片属于某个特定数字类的证据(evidence),我们对图片像素值进行加权求和。如果这个像素具有很强的证据说明这张图片不属于该类,那么相应的权值为负数,相反如果这个像素拥有有利的证据支持这张图片属于这个类,那么权值是正数。下面的图片显示了一个模型学习到的图片上每个像素对于特定数字类的权值。红色代表负数权值,蓝色代表正数权值。我们也需要加入一个额外的偏置量(bias),因为输入往往会带有一些无关的干扰量。因此对于给定的输入图片x
它代表的是数字i 的证据可以表示为其中代表数字i 类的偏置量,j 代表给定图片x
的像素索引用于像素求和。然后用softmax函数可以把这些证据转换成概率y:这里的softmax可以看成是一个激励(activation)函数或者链接(link)函数,把我们定义的线性函数的输出转换成我们想要的格式,也就是关于10个数字类的概率分布。因此,给定一张图片,它对于每一个数字的吻合度可以被softmax函数转换成为一个概率值。softmax函数可以定义为:展开等式右边的子式,可以得到:

但是更多的时候把softmax模型函数定义为前一种形式:把输入值当成幂指数求值,再正则化这些结果值。这个幂运算表示,更大的证据对应更大的假设模型(hypothesis)里面的乘数权重值。反之,拥有更少的证据意味着在假设模型里面拥有更小的乘数系数。假设模型里的权值不可以是0值或者负值。Softmax然后会正则化这些权重值,使它们的总和等于1,以此构造一个有效的概率分布。(更多的关于Softmax函数的信息,可以参考Michael
Nieslen的书里面的这个部分,其中有关于softmax的可交互式的可视化解释。)对于softmax回归模型可以用下面的图解释,对于输入的xs
加权求和,再分别加上一个偏置量,最后再输入到softmax函数中:如果把它写成一个等式,我们可以得到:

我们也可以用向量表示这个计算过程:用矩阵乘法和向量相加。这有助于提高计算效率。(也是一种更有效的思考方式)

更进一步,可以写成更加紧凑的方式:

实现回归模型

为了用python实现高效的数值计算,我们通常会使用函数库,比如NumPy,会把类似矩阵乘法这样的复杂运算使用其他外部语言实现。不幸的是,从外部计算切换回Python的每一个操作,仍然是一个很大的开销。如果你用GPU来进行外部计算,这样的开销会更大。用分布式的计算方式,也会花费更多的资源用来传输数据。TensorFlow也把复杂的计算放在python之外完成,但是为了避免前面说的那些开销,它做了进一步完善。Tensorflow不单独地运行单一的复杂计算,而是让我们可以先用图描述一系列可交互的计算操作,然后全部一起在Python之外运行。(这样类似的运行方式,可以在不少的机器学习库中看到。)

使用TensorFlow之前,首先导入它:

import tensorflow as tf

我们通过操作符号变量来描述这些可交互的操作单元,可以用下面的方式创建一个:

x = tf.placeholder(“float”, [None, 784])

x 不是一个特定的值,而是一个占位符placeholder
,我们在TensorFlow运行计算时输入这个值。我们希望能够输入任意数量的MNIST图像,每一张图展平成784维的向量。我们用2维的浮点数张量来表示这些图,这个张量的形状是[None,784
] 。(这里的None
表示此张量的第一个维度可以是任何长度的。)我们的模型也需要权重值和偏置量,当然我们可以把它们当做是另外的输入(使用占位符),但TensorFlow有一个更好的方法来表示它们:
Variable 。 一个Variable
代表一个可修改的张量,存在在TensorFlow的用于描述交互性操作的图中。它们可以用于计算输入值,也可以在计算中被修改。对于各种机器学习应用,一般都会有模型参数,可以用Variable
表示。

W = tf.Variable(tf.zeros([784,10]))

b = tf.Variable(tf.zeros([10]))

我们赋予tf.Variable 不同的初值来创建不同的Variable
:在这里,我们都用全为零的张量来初始化W 和b 。因为我们要学习W 和b
的值,它们的初值可以随意设置。注意, W
的维度是[784,10],因为我们想要用784维的图片向量乘以它以得到一个10维的证据值向量,每一位对应不同数字类。b
的形状是[10],所以我们可以直接把它加到输出上面。

现在,我们可以实现我们的模型啦。只需要一行代码!y = tf.nn.softmax(tf.matmul(x,W)
+ b)

首先,我们用tf.matmul(X,W) 表示x 乘以W ,对应之前等式里面的,这里x
是一个2维张量拥有多个输入。然后再加上b ,把和输入到tf.nn.softmax
函数里面。至此,我们先用了几行简短的代码来设置变量,然后只用了一行代码来定义我们的模型。TensorFlow不仅仅可以

使softmax回归模型计算变得特别简单,它也用这种非常灵活的方式来描述其他各种数值计算,从机器学习模型对物理学模拟仿真模型。一旦被定义好之后,我们的模型就可以在不同的设备上运行:计算机的CPU,GPU,甚至是手机!

训练模型

为了训练我们的模型,我们首先需要定义一个指标来评估这个模型是好的。其实,在机器学习,我们通常定义指

标来表示一个模型是坏的,这个指标称为成本(cost)或损失(loss),然后尽量最小化这个指标。但是,这两种方式是相同的。一个非常常见的,非常漂亮的成本函数是“交叉熵”(cross-entropy)。交叉熵产生于信息论里面的信息压缩编码技术,但是它后来演变成为从博弈论到机器学习等其他领域里的重要技术手段。它的定义如下:

y 是我们预测的概率分布, y’ 是实际的分布(我们输入的one-hot
vector)。比较粗糙的理解是,交叉熵是用来衡量我们的预测用于描述真相的低效性。更详细的关于交叉熵的解释超出本教程的范畴,但是你很有必要好好理解它。为了计算交叉熵,我们首先需要添加一个新的占位符用于输入正确值:

y_ = tf.placeholder(“float”, [None,10])

然后我们可以用计算交叉熵:

cross_entropy = -tf.reduce_sum(y_*tf.log(y))

首先,用tf.log 计算y 的每个元素的对数。接下来,我们把y_ 的每一个元素和tf.log(y)
的对应元素相乘。最后,用tf.reduce_sum
计算张量的所有元素的总和。(注意,这里的交叉熵不仅仅用来衡量单一的一对预测和真实值,而是所有100幅图片的交叉熵的总和。对于100个数据点的预测表现比单一数据点的表现能更好地描述我们的模型的性能。现在我们知道我们需要我们的模型做什么啦,用TensorFlow来训练它是非常容易的。因为TensorFlow拥有一张描述你各个计算单元的图,它可以自动地使用反向传播算法(backpropagation
algorithm)来有效地确定你的变量是

如何影响你想要最小化的那个成本值的。然后,TensorFlow会用你选择的优化算法来不断地修改变量以降低成本。

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

在这里,我们要求TensorFlow用梯度下降算法(gradient descent
algorithm)以0.01的学习速率最小化交叉熵。梯度下降算法(gradient descent
algorithm)是一个简单的学习过程,TensorFlow只需将每个变量一点点地往使成本不断降低的方向移动。当然TensorFlow也提供了其他许多优化算法:只要简单地调整一行代码就可以使用其他的算法。TensorFlow在这里实际上所做的是,它会在后台给描述你的计算的那张图里面增加一系列新的计算操作单元用于实现反向传播算法和梯度下降算法。然后,它返回给你的只是一个单一的操作,当运行这个操作时,它用梯度下降算法训练你的模型,微调你的变量,不断减少成本。现在,我们已经设置好了我们的模型。在运行计算之前,我们需要添加一个操作来初始化我们创建的变量:

init = tf.initialize_all_variables()

现在我们可以在一个Session 里面启动我们的模型,并且初始化变量:

sess = tf.Session()

sess.run(init)

然后开始训练模型,这里我们让模型循环训练1000次!

for i in range(1000):

batch_xs, batch_ys = mnist.train.next_batch(100)

sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

该循环的每个步骤中,我们都会随机抓取训练数据中的100个批处理数据点,然后我们用这些数据点作为参数替换之前的占位符来运行train_step
。使用一小部分的随机数据来进行训练被称为随机训练(stochastic training)-
在这里更确切的说是随机梯度下降训练。在理想情况下,我们希望用我们所有的数据来进行每一步的训练,因为这能给我们更好的训练结果,但显然这需要很大的计算开销。所以,每一次训练我们可以使用不同的数据子集,这样做既可以减少计算开销,又可以最大化地学习到数据集的总体特性。

评估我们的模型

那么我们的模型性能如何呢?

首先让我们找出那些预测正确的标签。tf.argmax
是一个非常有用的函数,它能给出某个tensor对象在某一维上的其数据最大值所在的索引值。由于标签向量是由0,1组成,因此最大值1所在的索引位置就是类别标签,比如tf.argmax(y,1)
返回的是模型对于任一输入x预测到的标签值,而tf.argmax(y_,1)
代表正确的标签,我们可以用tf.equal
来检测我们的预测是否真实标签匹配(索引位置一样表示匹配)。correct_prediction =
tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

这行代码会给我们一组布尔值。为了确定正确预测项的比例,我们可以把布尔值转换成浮点数,然后取平均值。例如,
[True, False, True, True] 会变成[1,0,1,1] ,取平均值后得到0.75 .

accuracy = tf.reduce_mean(tf.cast(correct_prediction,
“float”))最后,我们计算所学习到的模型在测试数据集上面的正确率。print
sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})

这个最终结果值应该大约是91%。

这个结果好吗?嗯,并不太好。事实上,这个结果是很差的。这是因为我们仅仅使用了一个非常简单的模型。不过,做一些小小的改进,我们就可以得到97%的正确率。最好的模型甚至可以获得超过99.7%的准确率!(想了解更多信息,可以看看这个关于各种模型的性能对比列表。)

经验案例

基于Tensorflow对MNIST数据集进行分类

机器学习导论(培训材料)

参考书目

参考资料

python测试工具

selenium

monkeyRunner

airtest

pytest

经验案例

参考书目

James《Google 软件测试之道》

Ron《软件测试》

参考资料

python库

网络库

网络库 ---- requests

底层网络接口 ---- socket

asyncio的HTTP客户端/服务器(PEP-3156) ---- aiohttp

网络爬虫框架

HTML/XML解析器

经验案例

参考书目

参考资料

https://www.python.org/

参考资料

  • 1
    点赞
  • 0
    评论
  • 2
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

lynchyueliu

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值