├── README.md ├── notes ├── 第1章 学习工具准备 │ ├── 1.1_翻墙.md │ ├── 1.2_typora.md │ ├── 1.3_Github Desktop.md │ └── 1.4_虚拟系统简介.md ├── 第2章 Python基础 │ ├── 2.1_Python基础 │ │ ├── 2.1.10_分支结构.md │ │ ├── 2.1.11_循环结构.md │ │ ├── 2.1.12_构造程序逻辑.md │ │ ├── 2.1.13_推导式.md │ │ ├── 2.1.14_文件操作.md │ │ ├── 2.1.15_编码问题.md │ │ ├── 2.1.16_深浅拷贝.md │ │ ├── 2.1.17_错误和异常.md │ │ ├── 2.1.1_历史介绍.md │ │ ├── 2.1.2_软件安装.md │ │ ├── 2.1.3_第一个小程序.md │ │ ├── 2.1.4_注释.md │ │ ├── 2.1.5_变量及数据类型.md │ │ ├── 2.1.6_输入、输出和格式化输出.md │ │ ├── 2.1.7_运算符.md │ │ ├── 2.1.8_字符串.md │ │ └── 2.1.9_常用数据类型.md │ ├── 2.2_Python进阶 │ │ ├── 2.2.1_函数 │ │ │ ├── 2.2.1.10_map()映射函数.md │ │ │ ├── 2.2.1.11_reduce()函数.md │ │ │ ├── 2.2.1.12_常用内置函数.md │ │ │ ├── 2.2.1.13_内置函数作业.md │ │ │ ├── 2.2.1.14_二分查找.md │ │ │ ├── 2.2.1.1_函数、返回值和参数.md │ │ │ ├── 2.2.1.2_函数的说明文档.md │ │ │ ├── 2.2.1.3_函数嵌套和作用域.md │ │ │ ├── 2.2.1.4_拆包和交换变量值.md │ │ │ ├── 2.2.1.5_学员管理系统.md │ │ │ ├── 2.2.1.6_递归.md │ │ │ ├── 2.2.1.7_lambda匿名函数.md │ │ │ ├── 2.2.1.8_sorted()排序函数.md │ │ │ ├── 2.2.1.9_filter过滤函数.md │ │ │ ├── 2.3.1.10_闭包和迭代器.md │ │ │ ├── 2.3.1.11_生成器.md │ │ │ ├── 2.3.1.12_装饰器.md │ │ │ └── 内置函数.xmind │ │ ├── 2.2.2_面向对象 │ │ │ ├── 2.2.2.1_函数式编程和面向对象编程的对比.md │ │ │ ├── 2.2.2.2_面向对象属性.md │ │ │ ├── 2.2.2.3_面向对象魔法方法.md │ │ │ ├── 2.2.2.4_实例应用.md │ │ │ ├── 2.2.2.5_面向对象继承.md │ │ │ └── 2.2.2.6_面向对象多态.md │ │ ├── 2.2.3_模块和包 │ │ │ ├── 2.2.3.10_面向对象版学员管理系统.md │ │ │ ├── 2.2.3.1_模块和包.md │ │ │ ├── 2.2.3.2_random模块.md │ │ │ ├── 2.2.3.3_sys模块.md │ │ │ ├── 2.2.3.4_JSON模块.md │ │ │ ├── 2.2.3.5_pickle模块.md │ │ │ ├── 2.2.3.6_os模块.md │ │ │ ├── 2.2.3.7_time模块.md │ │ │ ├── 2.2.3.8_正则表达式.md │ │ │ └── 2.2.3.9_re模块.md │ │ ├── 2.2.4_多任务编程 │ │ │ ├── 2.2.4.1_多线程.md │ │ │ └── 2.2.4.2_多进程.md │ │ └── 2.2.5_软件开发规范.md │ └── images │ │ ├── Guido Van Rossum.jpg │ │ ├── Unicode-utf8.jpg │ │ ├── Unicode-浏览器.jpg │ │ ├── and_or.png │ │ ├── hash讲解.png │ │ ├── os模块.png │ │ ├── process进程类的说明.png │ │ ├── re模块.png │ │ ├── time模块三种时间格式转换.png │ │ ├── 五星红旗.jpg │ │ ├── 函数定义说明文档.png │ │ ├── 分支条件公式.png │ │ ├── 异常处理.png │ │ ├── 异常处理过程.png │ │ ├── 懒惰模式.png │ │ ├── 操作系统和python.png │ │ ├── 数据的可变和不可变.png │ │ ├── 数据类型.png │ │ ├── 正方形.png │ │ ├── 浅拷贝.png │ │ ├── 深拷贝.png │ │ ├── 电脑间的同步原理.png │ │ ├── 类中的self.png │ │ ├── 贪婪模式.png │ │ ├── 软件开发规范.png │ │ └── 集合.png ├── 第3章 MySQL数据库 │ ├── 3.1_MySQL简介.md │ ├── 3.2_MySQL安装.md │ ├── 3.3.1_MySQL基础知识_1.md │ ├── 3.3.2_MySQL基础知识_2.md │ └── 3.4_Python操作MySQL.md ├── 第5章 Python爬虫 │ ├── 1.爬虫基础 │ │ ├── 6.1.1_爬虫基础理论.md │ │ └── 6.1.2_爬虫常用库的安装.md │ ├── 2.获取网页源代码 │ │ ├── 6.2.1_curl详解.md │ │ ├── 6.2.2_Urllib库详解.md │ │ └── 6.2.3_Requests库详解.md │ ├── 3.解析网页数据 │ │ ├── 6.3.1_正则表达式.md │ │ ├── 6.3.2_XPath库详解.md │ │ ├── 6.3.3_BeautifulSoup库详解.md │ │ ├── 6.3.4_PyQuery库详解.md │ │ ├── 6.3.5_Selenium库详解.md │ │ └── 6.3.6_Splash的使用.md │ ├── 4.反扒处理 │ │ ├── 6.4.1_验证码的识别.md │ │ ├── 6.4.2_代理池应用.md │ │ └── 6.4.3_模拟登陆.md │ ├── 5.爬虫框架 │ │ ├── 6.5.1_PySpider框架基本用法.md │ │ ├── 6.5.2_Scrapy框架的使用.md │ │ ├── 6.5.3_分布式爬虫.md │ │ └── 6.5.4_分布式爬虫的部署.md │ └── 6.实例应用 │ │ ├── 6.6.1_Requests+正则表达式爬取猫眼电影top100.md │ │ ├── 6.6.2_Requests+xpath爬取豆瓣电影top250.md │ │ ├── 6.6.3_分析Ajax来抓取今日头条街拍美图.md │ │ ├── 6.6.4_Selenium爬取淘宝美食.md │ │ └── 6.6.5_Scrapy+mongodb爬取链家二手房信息.md ├── 第6章 网络编程 │ ├── 7.1_网络编程基础 │ │ ├── 7.1.1_网络编程的基本概念.md │ │ ├── 7.1.2_Python网络编程.md │ │ ├── 7.1.3_HTTP协议.md │ │ └── 7.1.4_搭建Python自带Web服务器.md │ ├── 7.2_前端网络编程 │ │ └── 7.2.1_HTML │ │ │ ├── 8.1.1.1_Web语言:认识HTML.md │ │ │ ├── 8.1.1.2_认识HTML中的HT:深入了解超文本.md │ │ │ ├── 8.1.1.3_Web页面建设:构建模块.md │ │ │ ├── 8.1.1.4_Web镇之旅:连接起来.md │ │ │ └── 传智html基础 │ │ │ ├── CSS基础.md │ │ │ ├── JavaScript基础.md │ │ │ └── html基础.md │ ├── 7.3_网络编程框架 │ │ ├── 1.Flask Web开发 │ │ │ ├── 1_安装.md │ │ │ └── 2_应用的基本结构.md │ │ ├── 9.3_Flask简介.md │ │ └── Flask_zhiliao_笔记.md │ └── images │ │ ├── 1.png │ │ ├── 2.png │ │ ├── CSS布局常用属性.png │ │ ├── CSS文本常用属性.png │ │ ├── JavaScript数据类型.png │ │ ├── OSI七层模型.png │ │ ├── drink.jpg │ │ ├── python.jpg │ │ ├── 匈牙利命名风格.png │ │ ├── 盒子示意图.png │ │ └── 网络分层模型.jpg └── 第8章 Linux系统 │ └── Linux笔记.md └── 问题记录 └── 学习过程中遇到的各种电脑问题.md /README.md: -------------------------------------------------------------------------------- 1 | 这是一个开始从`Python`基础语法学习,扩展到以数据分析为目的的多元化学习。为了能够完整的学习这门语言以及涉及到的其他计算机知识,包括前端知识、数据库、爬虫、数据分析与可视化、网页开发、`Linux`等。通过记录笔记,让自己对所学的内容有更深刻的理解。 2 | -------------------------------------------------------------------------------- /notes/第1章 学习工具准备/1.1_翻墙.md: -------------------------------------------------------------------------------- 1 | # 翻墙 2 | 3 | 编程软件基本都是国外科技公司开发的,如果想要系统的学习一门编程软件第一步最好要学会如何翻墙。首先,国内很多下载盗版软件的网站太乱,不经意间你就下载了很多不需要的东西,真的是太恶心了!!!其次,python的很多安装包在安装时会因为国内网速的限制而不能下载,通过镜像下载又会有一些麻烦,不一定可以一次成功,所以最好还是可以直接翻墙下载。而且很多最新内容都是先在国外网站更新再被搬到国内的,想要快速追踪最新内容翻墙是必不可少的。由于我也只是小白,不会自己写代码翻墙,这里推荐一个我用到现在非常好用的收费`vpn`软件。目前用下来还是很好用的,希望不会被和谐掉,但是有时候主页网站登不上去,可能是因为浏览器有的时候会屏蔽这些翻墙网站。 4 | 5 | - 名称:天路云加速器 6 | - [网站]() 7 | - 网站上有详细的安装教程,目前用下来很稳定,很好用 8 | - PAC模式:登陆外网时不限制国内网站速度,所有有一些国外网站会进不去 9 | - 全局模式:限制国内网站速度,加速国外网站速度 10 | - 在安装python包时要改成全局模式 -------------------------------------------------------------------------------- /notes/第1章 学习工具准备/1.3_Github Desktop.md: -------------------------------------------------------------------------------- 1 | # Github Desktop 2 | 3 | 在学习编程前,可以下载`Github Desktop`用来管理自己的笔记和代码,把每天学习的内容更新到`Github`上,方便保存及日后修改学习。使用`Desktop`按键式菜单,要比使用`git`语言方便许多,初学者可以从`Desktop`开始学起。 -------------------------------------------------------------------------------- /notes/第1章 学习工具准备/1.4_虚拟系统简介.md: -------------------------------------------------------------------------------- 1 | # 虚拟系统简介 2 | 3 | 虚拟系统,也常被称为影子系统,是一种计算机软件,可以在现有的操作系统上虚拟出一个相同的环境,并在该虚拟环境中运行应用程序,而所有访问与改变系统的活动将会被限制在该环境下,意即虚拟系统与实体系统是隔离的,虚拟系统中的活动不会造成实体系统的改变。简单的说,就是你可以在虚拟系统里随意操作,当不需要这个系统是就把他删除掉,而不会影响电脑本身的系统。 4 | 5 | 如果想要实现双系统,最直接的办法是在一台电脑上安装两个系统。但是,由于大多数人买的电脑只有一个系统,要手动安装双系统会比较麻烦。比较简单的办法可以下载一个软件`VMWare`,这款软件可以在本机电脑上安装一个或多个虚拟系统,也不会影响本地系统的运行。 6 | 7 | **为什么要这么早的介绍虚拟系统呢?** 8 | 9 | 因为,在以后学习`Python`的过程中,会遇到很多不同的软件需要安装,每种软件的功能各有不同,适用的环境也不同,当你因为软件安装问题需要多次重新安装,或者需要多机器互动操作等问题时,就可以使用虚拟环境来解决。并且在虚拟系统里可以多次操作软件安装,环境配置等,可以更加熟悉系统和软件的应用。而且,当学习到分布式操作时,需要不同系统进行配合运行,早安装好也方便学习其他系统的操作。 10 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.10_分支结构.md: -------------------------------------------------------------------------------- 1 | ## 分支结构 2 | 3 | --- 4 | 5 | ### 应用场景 6 | 7 | 迄今为止,我们写的`Python`代码都是一条一条语句顺序执行,这种代码结构通常称之为顺序结构。然而仅有顺序结构并不能解决所有的问题,比如我们设计一个游戏,游戏第一关的通关条件是玩家获得1000分,那么在完成本局游戏后,我们要根据玩家得到分数来决定究竟是进入第二关,还是告诉玩家`“Game Over”`,这里就会产生两个分支,而且这两个分支只有一个会被执行。类似的场景还有很多,我们将这种结构称之为“分支结构”或“选择结构”。 8 | 9 | ### `if`语句的使用 10 | 11 | 在`Python`中,要构造分支结构可以使用`if`、`elif`和`else`关键字,但是在`Python`中不支持`switch...case`语句。所谓**关键字**就是有特殊含义的单词,像`if`和`else`就是专门用于构造分支结构的关键字,很显然你不能够使用它作为变量名(事实上,用作其他的标识符也是不可以)。下面的例子中演示了如何构造一个分支结构。在`Python`语言里,使用强制缩进来表示语句之间的结构。 12 | 13 | ```Python 14 | username = input('请输入用户名: ') 15 | password = input('请输入口令: ') 16 | # 用户名是admin且密码是123456则身份验证成功否则身份验证失败 17 | if username == 'admin' and password == '123456': 18 | print('身份验证成功!') 19 | else: 20 | print('身份验证失败!') 21 | ``` 22 | 23 | 唯一需要说明的是和`C/C++`、`Java`等语言不同,`Python`中没有用花括号来构造代码块而是使用了缩进的方式来设置代码的层次结构,如果`if`条件成立的情况下需要执行多条语句,只要保持多条语句具有相同的缩进就可以了,换句话说连续的代码如果又保持了相同的缩进那么它们属于同一个代码块,相当于是一个执行的整体。通常情况下,空格为一个制表符,即四个空格。 24 | 25 | 当然如果要构造出更多的分支,可以使用`if…elif…else…`结构,例如下面的分段函数求值。 26 | 27 | ```Python 28 | x = float(input('x = ')) 29 | if x > 1: 30 | y = 3 * x - 5 31 | elif x >= -1: 32 | y = x + 2 33 | else: 34 | y = 5 * x + 3 35 | print('f(%.2f) = %.2f' % (x, y)) 36 | ``` 37 | 38 | 当然根据实际开发的需要,分支结构是可以嵌套的,例如判断是否通关以后还要根据你获得的宝物或者道具的数量对你的表现给出等级(比如点亮两颗或三颗星星),那么我们就需要在`if`的内部构造出一个新的分支结构,同理`elif`和`else`中也可以再构造新的分支,我们称之为嵌套的分支结构,也就是说上面的代码也可以写成下面的样子。 39 | 40 | ```Python 41 | x = float(input('x = ')) 42 | if x > 1: 43 | y = 3 * x - 5 44 | else: 45 | if x >= -1: 46 | y = x + 2 47 | else: 48 | y = 5 * x + 3 49 | print('f(%.2f) = %.2f' % (x, y)) 50 | ``` 51 | 52 | > **说明:** 大家可以自己感受一下这两种写法到底是哪一种更好。在之前我们提到的`Python`之禅中有这么一句话“Flat is better than nested.”,之所以提倡代码“扁平化”是因为嵌套结构的**嵌套层次多了之后会严重的影响代码的可读性**,所以能使用扁平化的结构时就不要使用嵌套。 53 | 54 | 三目运算符也叫三元运算符或三元表达式,旨在简化简单条件语句的代码量。 55 | 56 | ```python 57 | a = 1 58 | b = 2 59 | 60 | c = a if a > b else b 61 | print(c) 62 | ``` 63 | 64 | 65 | 66 | ### 练习 67 | 68 | **练习1:英制单位英寸与公制单位厘米互换。** 69 | 70 | ```Python 71 | value = float(input('请输入长度: ')) 72 | unit = input('请输入单位: ') 73 | if unit == 'in' or unit == '英寸': 74 | print('%f英寸 = %f厘米' % (value, value * 2.54)) 75 | elif unit == 'cm' or unit == '厘米': 76 | print('%f厘米 = %f英寸' % (value, value / 2.54)) 77 | else: 78 | print('请输入有效的单位') 79 | ``` 80 | 81 | **练习2:百分制成绩转换为等级制成绩。** 82 | 83 | > **要求**:如果输入的成绩在90分以上(含90分)输出A;80分-90分(不含90分)输出B;70分-80分(不含80分)输出C;60分-70分(不含70分)输出D;60分以下输出E。 84 | 85 | ```Python 86 | score = float(input('请输入成绩: ')) 87 | if score >= 90: 88 | grade = 'A' 89 | elif score >= 80: 90 | grade = 'B' 91 | elif score >= 70: 92 | grade = 'C' 93 | elif score >= 60: 94 | grade = 'D' 95 | else: 96 | grade = 'E' 97 | print('对应的等级是:', grade) 98 | ``` 99 | **练习3:输入三条边长,如果能构成三角形就计算周长和面积。** 100 | 101 | ```Python 102 | a = float(input('a = ')) 103 | b = float(input('b = ')) 104 | c = float(input('c = ')) 105 | if a + b > c and a + c > b and b + c > a: 106 | print('周长: %f' % (a + b + c)) 107 | p = (a + b + c) / 2 108 | area = (p * (p - a) * (p - b) * (p - c)) ** 0.5 109 | print('面积: %f' % (area)) 110 | else: 111 | print('不能构成三角形') 112 | ``` 113 | > **说明:** 上面使用的通过边长计算三角形面积的公式叫做[海伦公式](https://zh.wikipedia.org/zh-hans/海伦公式)。 114 | 115 | 练习4:石头剪刀布游戏 116 | 117 | >这里涉及到引入函数模块,后面会学到 118 | 119 | ```python 120 | import random 121 | ''' 122 | 剪刀:0 石头:1 布:2 123 | ''' 124 | player = int(input("请输入你出什么:")) 125 | computer = random.randint(0, 2) # randint包含左右两端 126 | if (player == 0 and computer == 2) or (player == 1 and computer == 0) or (player == 2 and computer == 1): 127 | print(f'玩家出{player}, 电脑出{computer},玩家获胜') 128 | elif player == computer: 129 | print(f'玩家和电脑都出{player},平局') 130 | else: 131 | print(f'玩家出{player}, 电脑出{computer},电脑获胜') 132 | ``` 133 | 134 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.11_循环结构.md: -------------------------------------------------------------------------------- 1 | # 循环结构 2 | 3 | --- 4 | 5 | ## 应用场景 6 | 7 | 如果在程序中我们需要重复的执行某条或某些指令,例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向奔跑的指令。当然你可能已经注意到了,刚才的描述中不仅仅有需要重复的动作,还需要用到上一章讲的分支结构。再举一个简单的例子,我们要实现一个每隔1秒中在屏幕上打印一次"hello, world"并持续打印一个小时的程序,我们肯定不能够直接把`print('hello, world')`这句代码写3600遍,如果真的要这样做,那么编程的工作就太无聊乏味了。因此,我们还需要了解一下循环结构,有了循环结构我们就可以轻松的控制某件事或者某些事重复、重复、再重复的去执行。 8 | 9 | 在`Python`中构造循环结构有两种做法,一种是`for-in`循环,一种是`while`循环,不支持`do...while...`循环。 10 | 11 | ## `for-in`循环 12 | 13 | 如果明确的知道循环执行的次数或者要对一个容器进行迭代(后面会讲到),那么我们推荐使用`for-in`循环,例如下面代码中计算1~100求和的结果($\displaystyle \sum \limits_{n=1}^{100}n$)。 14 | 15 | ```Python 16 | sum = 0 17 | for x in range(101): 18 | sum += x 19 | print(sum) 20 | ``` 21 | 22 | 需要说明的是上面代码中的`range(101)`可以用来构造一个从0到100的取值范围,这样就可以构造出一个整数的序列并用于循环中,例如: 23 | 24 | - `range(101)`可以产生一个0到100的整数序列。 25 | - `range(1, 100)`可以产生一个1到99的整数序列。 26 | - `range(1, 100, 2)`可以产生一个1到99的奇数序列,其中**2是步长**,即数值序列的增量。 27 | 28 | 知道了这一点,我们可以用下面的代码来实现1~100之间的偶数求和。 29 | 30 | ```Python 31 | sum = 0 32 | for x in range(2, 101, 2): 33 | sum += x 34 | print(sum) 35 | ``` 36 | 37 | 也可以通过在循环中使用分支结构的方式来实现相同的功能,代码如下所示。 38 | 39 | ```Python 40 | sum = 0 41 | for x in range(1, 101): 42 | if x % 2 == 0: 43 | sum += x 44 | print(sum) 45 | ``` 46 | 47 | ## `while`循环 48 | 49 | 如果要构造**不知道具体循环次数**的循环结构,我们推荐使用`while`循环。`while`循环通过一个能够产生或转换出`bool`值的表达式来控制循环,表达式的值为`True`循环继续,表达式的值为`False`循环结束。下面我们通过一个“猜数字”的小游戏(计算机出一个1~100之间的随机数,人输入自己猜的数字,计算机给出对应的提示信息,直到人猜出计算机出的数字)来看看如何使用`while`循环。 50 | 51 | ```Python 52 | """ 53 | 猜数字游戏 54 | 计算机出一个1~100之间的随机数由人来猜 55 | 计算机根据人猜的数字分别给出提示大一点/小一点/猜对了 56 | """ 57 | import random 58 | 59 | answer = random.randint(1, 100) 60 | counter = 0 61 | while True: # True 可以改成 1 62 | counter += 1 63 | number = int(input('请输入: ')) 64 | if number < answer: 65 | print('大一点') 66 | elif number > answer: 67 | print('小一点') 68 | else: 69 | print('恭喜你猜对了!') 70 | break 71 | print('你总共猜了%d次' % counter) 72 | if counter > 7: 73 | print('你的智商余额明显不足') 74 | ``` 75 | 76 | 上面的代码中使用了`break`关键字来提前终止循环,需要注意的是`break`**只能终止它所在的那个循环**,这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。除了`break`之外,还有另一个关键字是`continue`,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。 77 | 78 | 和分支结构一样,循环结构也是可以嵌套的,也就是说在循环中还可以构造循环结构。下面的例子演示了如何通过嵌套的循环来输出一个九九乘法表。 79 | 80 | ```Python 81 | """ 82 | 输出乘法口诀表(九九表) 83 | """ 84 | for i in range(1, 10): 85 | for j in range(1, i + 1): 86 | print('%d*%d=%d' % (i, j, i * j), end='\t') 87 | print() 88 | ``` 89 | 90 | ## `break` `continue` 91 | 92 | `break continue`在`Python`里只能用在循环与距离。`break`用来结束整个循环,`continue`用来结束本轮循环,开启下一轮循环。 93 | 94 | ```python 95 | i = 0 96 | while i < 5: 97 | # 在使用continue时,要保证计数器在continue之前,不然会一直循环下去 98 | i += 1 99 | if i == 3: 100 | continue 101 | print(i) 102 | # 1 2 4 5 103 | 104 | i = 0 105 | while i < 5: 106 | i += 1 107 | if i == 3: 108 | break 109 | print(i) 110 | # 1 2 111 | ``` 112 | 113 | ## `for...else while...else`循环 114 | 115 | 循环正常结束后,执行`else`后的命令。 116 | 117 | ```python 118 | i = 1 119 | while i < 6: 120 | if i == 3: 121 | print('这次不算') 122 | i += 1 123 | break 124 | print('我错了') 125 | i += 1 126 | else: 127 | print('我原谅你') 128 | 129 | i = 1 130 | while i < 6: 131 | if i == 3: 132 | print('这次不算') 133 | i += 1 134 | continue 135 | print('我错了') 136 | i += 1 137 | else: 138 | print('我原谅你') 139 | ``` 140 | 141 | ```python 142 | name = 'itheima' 143 | for i in name: 144 | if i == 'e': 145 | print('遇到e不打印') 146 | break 147 | print(i) 148 | else: 149 | print('正常循环结束') 150 | 151 | name = 'itheima' 152 | for i in name: 153 | if i == 'e': 154 | print('遇到e不打印') 155 | break 156 | print(i) 157 | else: 158 | print('正常循环结束') 159 | ``` 160 | 161 | 162 | 163 | ### 练习 164 | 165 | #### 练习1:输入一个正整数判断是不是素数。 166 | 167 | > **提示**:素数指的是只能被1和自身整除的大于1的整数。 168 | 169 | ```Python 170 | """ 171 | 输入一个正整数判断它是不是素数 172 | 思路: 173 | 对一个数开根号,再循环除 174 | """ 175 | from math import sqrt 176 | 177 | num = int(input('请输入一个正整数: ')) 178 | end = int(sqrt(num)) 179 | is_prime = True 180 | for x in range(2, end + 1): 181 | if num % x == 0: 182 | is_prime = False 183 | break 184 | if is_prime and num != 1: 185 | print('%d是素数' % num) 186 | else: 187 | print('%d不是素数' % num) 188 | ``` 189 | 190 | #### 练习2:输入两个正整数,计算它们的最大公约数和最小公倍数。 191 | 192 | ```Python 193 | """ 194 | 输入两个正整数计算它们的最大公约数和最小公倍数 195 | """ 196 | x = int(input('x = ')) 197 | y = int(input('y = ')) 198 | # 如果x大于y就交换x和y的值 199 | if x > y: 200 | # 通过下面的操作将y的值赋给x, 将x的值赋给y 201 | x, y = y, x 202 | # 从两个数中较小的数开始做递减的循环 203 | for factor in range(x, 0, -1): 204 | if x % factor == 0 and y % factor == 0: 205 | print('%d和%d的最大公约数是%d' % (x, y, factor)) 206 | print('%d和%d的最小公倍数是%d' % (x, y, x * y // factor)) 207 | break 208 | ``` 209 | 210 | #### 练习3:打印如下所示的三角形图案。 211 | 212 | ```Python 213 | """ 214 | 打印三角形图案 215 | """ 216 | row = int(input('请输入行数: ')) 217 | for i in range(row): 218 | for _ in range(i + 1): 219 | print('*', end='') 220 | print() 221 | 222 | 223 | for i in range(row): 224 | for j in range(row): 225 | if j < row - i - 1: 226 | print(' ', end='') 227 | else: 228 | print('*', end='') 229 | print() 230 | 231 | 232 | for i in range(row): 233 | for _ in range(row - i - 1): 234 | print(' ', end='') 235 | for _ in range(2 * i + 1): 236 | print('*', end='') 237 | print() 238 | ``` 239 | 240 | 打印结果: 241 | 242 | ``` 243 | * 244 | ** 245 | *** 246 | **** 247 | ***** 248 | 249 | * 250 | ** 251 | *** 252 | **** 253 | ***** 254 | 255 | * 256 | *** 257 | ***** 258 | ******* 259 | ********* 260 | ``` 261 | 262 | 263 | 264 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.12_构造程序逻辑.md: -------------------------------------------------------------------------------- 1 | ## 构造程序逻辑 2 | 3 | --- 4 | 5 | 学完前面的几个章节后,我觉得有必要在这里带大家做一些练习来巩固之前所学的知识,虽然迄今为止我们学习的内容只是`Python`的冰山一角,但是这些内容已经足够我们来构建程序中的逻辑。对于编程语言的初学者来说,在学习了`Python`的核心语言元素(变量、类型、运算符、分支结构、循环结构等)之后,必须做的一件事情就是尝试用所学知识去解决现实中的问题,换句话说就是锻炼自己把用人类自然语言描述的算法(解决问题的方法和步骤)翻译成Python代码的能力,而这件事情必须通过大量的练习才能达成。 6 | 7 | 我们在本章为大家整理了一些经典的案例和习题,希望通过这些例子,一方面帮助大家巩固之前所学的`Python`知识,另一方面帮助大家了解如何建立程序中的逻辑以及如何运用一些简单的算法解决现实中的问题。 8 | 9 | ### 经典的例子 10 | 11 | 1. 寻找**水仙花数**。 12 | 13 | > **说明**:水仙花数也被称为超完全数字不变数、自恋数、自幂数、阿姆斯特朗数,它是一个3位数,该数字每个位上数字的立方之和正好等于它本身,例如:$1^3 + 5^3+ 3^3=153$。 14 | 15 | ```Python 16 | for num in range(100, 1000): 17 | low = num % 10 18 | mid = num // 10 % 10 19 | high = num // 100 20 | if num == low ** 3 + mid ** 3 + high ** 3: 21 | print(num) 22 | ``` 23 | 24 | 在上面的代码中,我们通过整除和求模运算分别找出了一个三位数的个位、十位和百位,这种小技巧在实际开发中还是常用的。用类似的方法,我们还可以实现将一个正整数反转,例如:将12345变成54321,代码如下所示。 25 | 26 | ```Python 27 | num = int(input('num = ')) # 对输入的变量转换为整型 28 | reversed_num = 0 29 | while num > 0: 30 | reversed_num = reversed_num * 10 + num % 10 31 | num //= 10 32 | print(reversed_num) 33 | ``` 34 | 35 | 2. **百钱百鸡**问题。 36 | 37 | > **说明**:百钱百鸡是我国古代数学家[张丘建](https://baike.baidu.com/item/%E5%BC%A0%E4%B8%98%E5%BB%BA/10246238)在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?翻译成现代文是:公鸡5元一只,母鸡3元一只,小鸡1元三只,用100块钱买一百只鸡,问公鸡、母鸡、小鸡各有多少只? 38 | 39 | ```Python 40 | for x in range(0, 20): 41 | for y in range(0, 33): 42 | z = 100 - x - y 43 | if 5 * x + 3 * y + z / 3 == 100: 44 | print('公鸡: %d只, 母鸡: %d只, 小鸡: %d只' % (x, y, z)) 45 | ``` 46 | 47 | 上面使用的方法叫做**穷举法**,也称为**暴力搜索法**,这种方法通过一项一项的列举备选解决方案中所有可能的候选项并检查每个候选项是否符合问题的描述,最终得到问题的解。这种方法看起来比较笨拙,但对于运算能力非常强大的计算机来说,通常都是一个可行的甚至是不错的选择,而且问题的解如果存在,这种方法一定能够找到它。 48 | 49 | 3. **CRAPS赌博游戏**。 50 | 51 | > **说明**:`CRAPS`又称花旗骰,是美国拉斯维加斯非常受欢迎的一种的桌上赌博游戏。该游戏使用两粒骰子,玩家通过摇两粒骰子获得点数进行游戏。简单的规则是:玩家第一次摇骰子如果摇出了7点或11点,玩家胜;玩家第一次如果摇出2点、3点或12点,庄家胜;其他点数玩家继续摇骰子,如果玩家摇出了7点,庄家胜;如果玩家摇出了第一次摇的点数,玩家胜;其他点数,玩家继续要骰子,直到分出胜负。 52 | 53 | ```Python 54 | """ 55 | Craps赌博游戏 56 | 我们设定玩家开始游戏时有1000元的赌注 57 | 游戏结束的条件是玩家输光所有的赌注 58 | """ 59 | from random import randint 60 | 61 | money = 1000 62 | while money > 0: 63 | print('你的总资产为:', money) 64 | needs_go_on = False 65 | while True: 66 | debt = int(input('请下注: ')) 67 | if 0 < debt <= money: 68 | break 69 | first = randint(1, 6) + randint(1, 6) 70 | print('玩家摇出了%d点' % first) 71 | if first == 7 or first == 11: 72 | print('玩家胜!') 73 | money += debt 74 | elif first == 2 or first == 3 or first == 12: 75 | print('庄家胜!') 76 | money -= debt 77 | else: 78 | needs_go_on = True 79 | while needs_go_on: 80 | needs_go_on = False 81 | current = randint(1, 6) + randint(1, 6) 82 | print('玩家摇出了%d点' % current) 83 | if current == 7: 84 | print('庄家胜') 85 | money -= debt 86 | elif current == first: 87 | print('玩家胜') 88 | money += debt 89 | else: 90 | needs_go_on = True 91 | print('你破产了, 游戏结束!') 92 | ``` 93 | 94 | ### 有用的练习 95 | 96 | 1. 生成**斐波那契数列**的前20个数。 97 | 98 | > **说明**:斐波那契数列`(Fibonacci sequence)`,又称黄金分割数列,是意大利数学家莱昂纳多·斐波那契`(Leonardoda Fibonacci)`在《计算之书》中提出一个在理想假设条件下兔子成长率的问题而引入的数列,所以这个数列也被戏称为"兔子数列"。斐波那契数列的特点是数列的前两个数都是1,从第三个数开始,每个数都是它前面两个数的和,形如:`1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`。斐波那契数列在现代物理、准晶体结构、化学等领域都有直接的应用。 99 | 100 | ```python 101 | n = 1 102 | m = 1 103 | 104 | for i in range(20): 105 | print(n, end='\t') 106 | n, m = m, n + m 107 | ``` 108 | 109 | 2. 找出10000以内的**完美数**。 110 | 111 | > **说明**:完美数又称为完全数或完备数,它的所有的真因子(即除了自身以外的因子)的和(即因子函数)恰好等于它本身。例如:6`($6=1+2+3$)`和28`($28=1+2+4+7+14$)`就是完美数。完美数有很多神奇的特性,有兴趣的可以自行了解。 112 | 113 | ```python 114 | for i in range(1, 10001): 115 | s = 0 116 | for k in range(1, i): 117 | if i % k == 0: 118 | s += k 119 | if i == s: 120 | print(i, end='\t') 121 | ``` 122 | 123 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.13_推导式.md: -------------------------------------------------------------------------------- 1 | # 推导式 2 | 3 | --- 4 | 5 | 1. 用一句话来生成一个列表 `[结果 for循环]` 6 | 2. 不要用推导式处理过分复杂的东西 7 | 3. 没有元组推导式---元组不能增删改 8 | 9 | ## 列表推导式 10 | 11 | ```python 12 | lst = ['python' + str(i) for i in range(1, 16)] 13 | print(lst) 14 | 15 | lst = [i for i in range(100) if i%2 == 1] 16 | print(lst) 17 | 18 | lst = [i ** 2 for i in range(1, 100) if i % 3 == 0] 19 | print(lst) 20 | 21 | names = [['Tom','Billy','Jefferson','Andrew','Wesley','Joe'],['Alice','Jill','Ana','Wendy','Jennifer','Sherry','Eva']] 22 | lst = [name for line in manes for name in line if name.count('e') == 2] 23 | print(lst) 24 | ``` 25 | 26 | ## 字典推导式 27 | 28 | ```python 29 | lst = [11,22,33,44] 30 | dic = {i:lst[i] for i in range(len(lst)) if i < 2} 31 | print(dic) 32 | 33 | # 字典键值装换 34 | dic = {'jj':'林俊杰', 'jay':'周杰伦', 'zs':'赵四', 'ln':'刘能'} 35 | dic1 = {v : k for k,v in dic.items()} 36 | print(dic1) 37 | ``` 38 | 39 | ## 集合推导式 40 | 41 | ```python 42 | s = {i for i in range(1000)} 43 | print(s) 44 | 45 | lst = [1,2,1,3,2,4,5] 46 | s = set(lst) 47 | print(s) 48 | s1 = {i for i in lst} 49 | print(s1) 50 | ``` 51 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.14_文件操作.md: -------------------------------------------------------------------------------- 1 | # 文件操作 2 | 3 | --- 4 | 5 | 关于文件的操作主要包括:打开文件,得到文件句柄并赋值给一个变量;通过句柄对文件进行操作,读取本地文件或者下载文件到本地;最后是关闭文件。 6 | 7 | ## 打开关闭文件 8 | 9 | 必须先用`Python`内置的`open()`函数打开一个文件,创建一个`file`对象,相关的方法才可以调用它进行读写 10 | 11 | ```python 12 | f = open('a.txt', mode='rt',encoding='utf-8') 13 | f.close() 14 | ``` 15 | 16 | `f.close()`是向操作系统发送请求,要求操作系统关闭打开的文件,文件打开后,一定要在程序结束前关闭! 17 | 18 | `with`语句:为了防止忘记关闭文件,`Python`的上下文管理`with`语句可以很方便的使用 19 | 20 | ```python 21 | with open('a.txt', mode='rt', encoding='utf-8') as f: 22 | pass 23 | # 打开多个文件 24 | with open('a.txt', mode='rt', encoding='utf-8') as f,open('b.txt', mode='rt', encoding='utf-8')as f1: 25 | pass 26 | ``` 27 | 28 | ## 文件基本操作 29 | 30 | - `r`:只读模式, 默认模式,文件必须存在,不存在则抛出异常 31 | - `w`:只写模式, 不可读,文件不存在则创建,存在则清空内容 32 | - `a`:追加模式, 可读,可写,文件不存在则创建,存在则在最后一行追加内容 33 | 34 | 用"+"可以表示同时读写某个文件 35 | 36 | - `r+` 可读可写 37 | - `w+` 可读可写 消除文件内容,然后以写读的方式打开文件 38 | - `a+` 可读可写 以读写方式打开文件,并把文件指针移到文件尾   39 | 40 | **注意:**`r`默认打开的是`text`格式,`rb,wb,ab`读取到的内容都是`byte`字节,写入时也要提供字节类型,后面的字符编码不能添加,默认打开模式为`r`. 41 | 42 | ```python 43 | with open('a.txt', mode='rb') as f: 44 | a = f.read() 45 | print(a) #输出为二进制b'\xe6\xaf\x8f\xe5\xa4\xa9\xe9\x83\xbd\xe5\xad\xa6\xe4\xb9\xa0' 46 | print(a.decode())#每天都学习 47 | ``` 48 | 49 | `rb`模式每次读取一个字节,`rt`模式每次读取的是一个字符串 50 | 51 | ```python 52 | with open('a.txt', mode='rb',) as f: 53 | a = f.read(3) 54 | print(a)#b'\xe6\xaf\x8f' 55 | with open('a.txt', mode='rt',encoding='utf-8') as f: 56 | print(f.read(2))#每天 57 | ``` 58 | 59 | ```python 60 | with open('a.txt', mode='rt',encoding='utf-8') as f: 61 | print(f.read(2))#每天 读取前面两个字符串 62 | with open('a.txt', mode='rt',encoding='utf-8') as f: 63 | print(f.read())全部读取 64 | with open('a.txt', mode='rt',encoding='utf-8') as f: 65 | print(f.readline())#每次读取一行 66 | with open('a.txt', mode='rt',encoding='utf-8') as f: 67 | print(f.readlines())#读取文件的全部行,以列表形式返回 68 | print(f.readable())#是否可读 69 | ``` 70 | 71 | ```python 72 | with open('b.txt', mode='wb') as f: 73 | f.write('abc你好'.encode('utf-8')) #写入内容至b.txt 74 | # f.writelines(a)# 将列表写入,字节情况下无法写入 75 | print(f.readable())# Fales 76 | print(f.writable())# True 77 | with open('b.txt', mode='a', encoding='utf-8') as f: 78 | print(f.tell())#鼠标指针当前位置 79 | f.write('qwe')# 在文件内容后面添加'qwe' 80 | print(f.tell())#鼠标指针当前位置 81 | ``` 82 | 83 | 控制指针移动: 84 | 85 | `f.seek(offset,whence)` 86 | 87 | `offset`:代表控制指针移动的字节数 88 | 89 | `whence`:代表参照什么位置移动 90 | 91 | - `whence =0`:参照文件开头 **特殊:**可以在`t`和`b`模式下使用 92 | - `whence =1`:参照当前所在位置,必须在`b`模式下使用 93 | - `whence =2`:参照文件末尾,必须在`b`模式下使用 94 | 95 | ```python 96 | with open('a.txt', mode='rt', encoding='utf-8') as f: 97 | f.seek(6, 0) # 移动的是字节数,三个字节为一个汉字 98 | msg = f.read(1) 99 | print(msg) 100 | 101 | with open('a.txt', mode='rb') as f: 102 | f.seek(3, 1) 103 | msg = f.read(6) 104 | msg = f.read(5) # 报错,因为汉字为三个字节 105 | print(msg.decode('utf-8')) 106 | 107 | #参照末尾 108 | with open('a.txt', mode='rb') as f: 109 | f.seek(-3, 2) 110 | print(f.tell()) 111 | msg = f.read(3) 112 | print(msg.decode('utf-8')) 113 | ``` 114 | 115 | ## 文件修改 116 | 117 | **方式一:** 118 | 119 | 将文件内容由硬盘全部读入内存,在内存中完成修改,将内存中修改的结果覆盖写会硬盘 120 | 121 | ```python 122 | with open('a.txt', mode='rt', encoding='utf-8') as f: 123 | all_data = f.read() 124 | all_data = all_data.replace('你','zfj') 125 | 126 | with open('a.txt', mode='wt', encoding='utf-8') as f: 127 | f.write(all_data) 128 | ``` 129 | 130 | **方式二:** 131 | 132 | 1.以读的方式打开源文件,以写的方式打开一个临时文件 133 | 134 | 2.从源文件中每读一行内容,修改完毕后写入临时文件,直到源文件读取完毕 135 | 136 | 3.删掉源文件,将临时文件重命名为源文件 137 | 138 | ```python 139 | import os 140 | with open('a.txt', mode='rt', encoding='utf-8') as f, open('a_swap.txt',mode='wt', encoding='utf-8')as f1: 141 | for i in f: 142 | f1.write(i.replace('哎呀呀','zfj')) 143 | os.remove('a.txt') 144 | os.rename('a_swap.txt', 'a.txt') 145 | ``` 146 | 147 | **文件备份** 148 | 149 | ```python 150 | old_name = input('请输入需要备份的文件名:') 151 | index = old_name.rfind('.') 152 | new_name = old_name[:index] + '[备份]' + old_name[index:] 153 | 154 | with open('test.txt', mode='rb') as old_f, open(new_name, mode='wb') as new_f: 155 | while True: 156 | con = old_f.read(1024) 157 | if len(con) == 0: 158 | break 159 | new_f.write(con) 160 | ``` 161 | 162 | 总结: 163 | 164 | 方式一:在文件修改过程中硬盘上始终一份数据,内存占用过多,不适用于大文件 165 | 166 | 方式二**:**在同一时刻内存中只存放源文件一行内容,不会占用过多内存,缺点是在文件修改过程中硬盘同时存在两份数据 167 | 168 | ## `Json`文件处理 169 | 170 | `JSON`是一种轻量级的数据交换格式,它是基于`ECMAScript`的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简介和清晰的层次结构使得`JSON`成为理想的数据交换语言。主要代码:`dump/dumps/load/loads` 171 | 172 | ## 基本用法 173 | 174 | ```python 175 | import json 176 | 177 | params = { 178 | 'name': '哈哈' 179 | } 180 | json_str = json.dumps(params, ensure_ascii=False) 181 | print(json_str) 182 | ``` 183 | 184 | ## 写入本地 185 | 186 | ```python 187 | import json 188 | 189 | params = { 190 | 'name': '哈哈' 191 | } 192 | with open('person.txt', 'w', encoding='utf-8') as f: 193 | json.dump(params, f, ensure_ascii=False) 194 | ``` 195 | 196 | ## `CSV`文件处理 197 | 198 | 纯文本文件,使用某个字符集;有记录组成,每行是一条记录;每条记录被分隔符分离字段;每条记录都有同样的字段序列。 199 | 200 | ```python 201 | # 以列表读取文件 202 | import csv 203 | 204 | with open('stock.csv', 'r') as f: 205 | reader = csv.reader(f) 206 | # 去掉第一行的标签名称 207 | next(reader) 208 | for x in reader: 209 | name = x[3] 210 | volumn = x[-1] 211 | print({ 212 | 'name': name, 213 | 'volumn': volumn 214 | }) 215 | 216 | # 以字典读取文件 217 | with open('stock.csv', 'r') as f: 218 | # 使用DictReader创建的reader对象不会包含标题行 219 | # reader是一个迭代器,遍历这个迭代器,返回是一个字典 220 | reader = csv.DictReader(f) 221 | for x in reader: 222 | print(x) 223 | ``` 224 | 225 | ```python 226 | # 写入csv文件 227 | import csv 228 | 229 | # 以列表写入 230 | headers = ['username', 'age', 'height'] 231 | values = [ 232 | ('zhangsan',18,180), 233 | ('lisi',19,190) 234 | ] 235 | with open('classroom.csv', 'w', encoding='utf-8', newline='') as f: 236 | writer = csv.writer(f) 237 | writer.writerow(headers) 238 | writer.writerows(values) 239 | # 以字典写入 240 | headers = ['username', 'age', 'height'] 241 | values = [ 242 | {'name': 'zhangsan','age': 18, 'height': 180}, 243 | {'name': 'lisi', 'age': 19, 'height': 190} 244 | ] 245 | with open('classroom1.csv', 'w', encoding='utf-8', newline='') as f: 246 | writer = csv.DictWriter(f, headers) 247 | # 要手动写入表头 248 | writer.writerheader() 249 | writer.writerows(values) 250 | ``` 251 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.16_深浅拷贝.md: -------------------------------------------------------------------------------- 1 | # 深浅拷贝 2 | 3 | --- 4 | 5 | 1. **深拷贝: `lst1 = lst2`** 6 | 7 | ![深拷贝](D:\repository\PythonNotes\notes\第2章 Python基础\images\深拷贝.png) 8 | 9 | ```python 10 | import copy 11 | 12 | lst1 = ['金毛狮王','紫衫龙王','青翼蝠王','白眉鹰王',['张无忌','赵敏','周芷若']] 13 | lst2 = copy.deepcopy(lst1) 14 | lst1[4].append('小昭') 15 | print(lst1) 16 | print(lst2) 17 | print(id(lst1)) 18 | print(id(lst2)) 19 | ``` 20 | 21 | 深拷贝:无论列表里嵌套了几层,原列表的改动不会改变新列表的内容。两个列表的内存地址不同。 22 | 23 | 24 | 25 | 2. **浅拷贝: `lst2 = lst1[:] lst2 = lst1.copy()`** 26 | 27 | ![浅拷贝](D:\repository\PythonNotes\notes\第2章 Python基础\images\浅拷贝.png) 28 | 29 | ```python 30 | import copy 31 | 32 | lst1 = ['金毛狮王','紫衫龙王','青翼蝠王','白眉鹰王',['张无忌','赵敏','周芷若']] 33 | lst2 = lst1.copy() 34 | lst1[4].append('小昭') 35 | lst1.append('谢逊') 36 | print(lst1) 37 | print(lst2) 38 | print(id(lst1)) 39 | print(id(lst2)) 40 | ``` 41 | 42 | 浅拷贝:第一层列表属于深拷贝,改变原列表内容,新列表不会变;但是第二层以上的拷贝内容就是浅拷贝,原列表的改动,新列表也会变。两个列表的内存地址不同。 43 | 44 | 45 | 46 | 3. **总结** 47 | 48 | - 复制没有创建新对象 49 | - 浅拷贝只拷贝第一层内容 50 | - 深拷贝, 把这个对象的内部内容全部拷贝一份 `deepcopy` -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.17_错误和异常.md: -------------------------------------------------------------------------------- 1 | # 错误和异常 2 | 3 | --- 4 | 5 | ## 什么是异常 6 | 7 | 在编写程序的时候,错误是难免的,入语法错误、逻辑错误等。当`Python`检测到一个错误的解释器就无法执行下去,于是抛出响应信息,这些可以笼统的称为异常信息。即便`Python`程序的语法正确,在运行的时候也有可能发生错误。运行期检测到的错误称为异常。异常处理的意义:当程序运行的时候出现异常,会导致程序终止运行,为了避免这种情况,需要预先对可能出现的异常进行处理,这样一旦出现该异常,就可以使用另一种方式解决问题,不会导致程序终止。 8 | 9 | ![异常处理](D:\repository\PythonNotes\notes\第2章 Python基础\images\异常处理.png) 10 | 11 | ## 异常类型 12 | 13 | `NameError IndexError keyError EOFError FileNotFoundError ValueError ModuleNotFoundError...` 14 | 15 | 1. 当你要处理的内容不确定的时候最容易出错: 16 | 1. 有用户参与 17 | 2. 外界数据接入 18 | 3. 从文件中或网上读取 19 | 20 | 2. 当有多行报错的时候是为什么? 21 | 22 | 在嵌套调用的过程中,内部的代码出了问题,外部所有的调用的地方都成为报错追溯信息的一部分 23 | 24 | **怎么解决**:首先找你写的代码,出错的哪一行,看看能不能看出问题,如果不行就百度 25 | 26 | ## 异常处理过程 27 | 28 | 1. 单分支:异常处理必须与实际报错一致 29 | 2. 多分支:从上到下报错的代码只要找到一个和报错类型相符的分支就执行分支代码,然后退出分支。如果找不到,会一直往下走,最后还是没有找到会报错 30 | 31 | ![异常处理过程](D:\repository\PythonNotes\notes\第2章 Python基础\images\异常处理过程.png) 32 | 33 | ```python 34 | l = ['login','register'] 35 | for num,i in enumrate(l,1): 36 | print(num,i) 37 | try: 38 | num = int(input('num >>>')) 39 | print(l[num-1]) 40 | except (ValueError,IndexError): # 异常处理必须与实际报错一致,多分支合并 41 | print('您的输入不合法') 42 | ``` 43 | 44 | 3. 万能异常 45 | 46 | - 所有程序开发完用 47 | - `try:...except Exception as e: print(e)`打印出错误信息 48 | - `try:...except:` 49 | - `try:...except(...):...except Exception as e:` 50 | - 多分支加万能异常 51 | - 万能异常放最后 52 | 4. `else`分支 53 | 54 | ```python 55 | try: 56 | print('aaa') 57 | name 58 | [][1] 59 | except NameError: 60 | print('name error') 61 | except IndexError: 62 | print('index error') 63 | else: # 当try中的代码不发生异常时,执行else 64 | print('else') 65 | ``` 66 | 67 | 5. `finally`分支 68 | 1. 即使遇到报错,程序结束,也会先执行`finally`中代码,然后再执行程序 69 | 2. 用来回收一些操作系统的资源:数据库连接,打开的文件句柄,网络连接 70 | 3. `try...except` `try...except...else` `try...finally` `try...except...finally` 71 | 4. `try...except...else...finally` 72 | 73 | ```python 74 | try: 75 | print('aaa') 76 | name 77 | [][1] 78 | except NameError: 79 | print('name error') 80 | except IndexError: 81 | print('index error') 82 | else: # 当try中的代码不发生异常时,执行else 83 | print('else') 84 | finally: # 无论如何都会被执行 85 | print('finally') 86 | ``` 87 | 88 | ## 主动抛出异常 89 | 90 | `raise ValueError('你写的不对')` 91 | 92 | ```python 93 | # 打印异常信息, 94 | # traceback模块精确模仿Python解释器stack trace行为。应尽量使用这个模块,可以在控制台更直观的显示异常 95 | import traceback 96 | try: 97 | print(1/0) 98 | except: 99 | traceback.print_exc() 100 | ``` 101 | 102 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.1_历史介绍.md: -------------------------------------------------------------------------------- 1 | # python历史介绍 2 | 3 | `Python`是一种面向对象、函数式编程的解释型程序设计语言,需要`Python`解释器进行解释运行。`Python`语法简洁、清晰和灵活。`Python`拥有大量的第三方库、活跃的开源社区和完善的模块文档,大量三方库都托管在`Github`上,实现功能较为方便。`Python`是一种脚本语言,解释器把程序翻译成计算机可执行的二进制代码,`Python`的官方解释器称为`CPython`。 4 | 5 | `Life is short, you need Python` 6 | 7 | 全栈工程师,也称为全端工程师(同时具备前端和后台能力),是指掌握多种技能,并能利用多种技能独立完成产品的人,英文为`Full Stack Engineer`。`Python`全栈工程师是指在精通`Python`编程语言的前提下,对于其他上下游的技术也有足够的了解和掌握。 8 | 9 | **创始人**: `Guido Van Rossum` 荷兰人 10 | 11 | ![Guido Van Rossum](D:\repository\PythonNotes\notes\第2章 Python基础\images\Guido Van Rossum.jpg) 12 | 13 | **`Python`名字起源**: 电视剧《蒙蒂蟒蛇的飞行马戏团》 14 | 15 | **`Python`希望达成的目标**: 在`C`和`Shell`之间创建全功能、易学、可扩展的语言 16 | 17 | **`Python`发展史**: 18 | 19 | - 1989年: 开发,圣诞节,阿姆斯特丹 20 | - 1991年: 完成`Python`的第一个编译器 21 | - 1994年: `Python 1.0`正式发布 22 | - 2000年: `Python 2.0`版本正式发布 23 | - 2008年: `Python 3.0`版本正式发布, 同时2.7版本在2020年后不再更新 24 | 25 | **`Python`优点** 26 | 27 | - 简单和明确,做一件事只有一种方法 28 | - 学习曲线低,跟其他很多语言相比,`Python`更容易上手 29 | - 开放源代码,拥有强大的社区和生态圈 30 | - 解释型语言,天生具有平台可移植性 31 | - 对两种主流的编程范式(面向对象编程和函数式编程)都提供了支持 32 | - 可扩展性和可嵌入性,例如在`Python`中可以调用`C/C++`代码 33 | - 代码规范程度高,可读性强,适合有代码洁癖和强迫症的人群 34 | 35 | **`Python`缺点** 36 | 37 | - 执行效率稍低,因此计算密集型任务可以由`C/C++`编写。 38 | - 代码无法加密,但是现在很多公司都不销售卖软件而是销售服务,这个问题会被弱化。 39 | - 在开发时可以选择的框架太多(如`Web`框架就有100多个),有选择的地方就有错误。 40 | 41 | **`Python`应用领域** 42 | 43 | 目前Python在**`Web`应用开发、云基础设施、`DevOps`、网络数据采集(爬虫)、数据分析挖掘、机器学习**等领域都有着广泛的应用,因此也产生了`Web`后端开发、数据接口开发、自动化运维、自动化测试、科学计算和可视化、数据分析、量化交易、机器人开发、自然语言处理、图像识别等一系列相关的职位。 44 | 45 | **目前各类语言排名** 46 | 47 | | 排名 | 语言 | 功能 | 48 | | ---- | ---------- | ---------------------------------------- | 49 | | 1 | Java | 企业级开发--坑少 | 50 | | 2 | C | 底层设计语言,游戏引擎内核 | 51 | | 3 | C++ | 游戏开发 | 52 | | 4 | Python | 爬虫,大数据,人工智能(很难),网页应用 | 53 | | 5 | C#(微软) | 家用游戏机--坑少 | 54 | | 6 | VB | 国营企业,一些大学用 | 55 | | 7 | PHP | 开发动态网站快--坑少 | 56 | | 8 | JavaScript | 网页开发 | 57 | | 9 | SQL | 数据库 | 58 | | 10 | Ruby | 脚本语言 | 59 | 60 | **`Python`是一门怎样的语言** 61 | 62 | - 编译型和解释型的区别 63 | 64 | - 编译型:必须先全部编译在运行,编译慢但运行快,所以游戏一般是编译型 65 | - 解释型:代码实时编译,编译快但运行慢,`python`是一门解释型语言 66 | 67 | | 编译型 | 解释型 | 混合型 | 68 | | -------- | ---------- | ------ | 69 | | C | JavaScript | JAVA | 70 | | C++ | Python | C# | 71 | | GO | Ruby | | 72 | | Swift | PHP | | 73 | | Object-C | Perl | | 74 | | Pascal | Erlang | | 75 | 76 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.2_软件安装.md: -------------------------------------------------------------------------------- 1 | # Python相关软件安装 2 | 3 | `Python`和`Pycharm`下载和安装教程可网络搜索教程 -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.3_第一个小程序.md: -------------------------------------------------------------------------------- 1 | # 第一个小程序 2 | 3 | >刚开始就直接进入`Python`程序学习可能会比较枯燥,所以在开始学习之前先介绍两个有趣的小程序,可能对于新手来说会更有趣。刚开始接触可能看不懂,可以先把代码复制到`pycharm`里运行一遍,看看运行结果。 4 | 5 | --- 6 | 7 | 8 | 9 | ## 使用`turtle`函数画图 10 | 11 | ```python 12 | # 在使用函数时,如果不是内置函数,首先需要进行导入 13 | import turtle 14 | # 设置画笔的粗细和颜色 15 | turtle.pensize(4) 16 | turtle.pencolor('red') 17 | # forward 表示向前 18 | # right 表示向右转90度 19 | turtle.forward(100) 20 | turtle.right(90) 21 | turtle.forward(100) 22 | turtle.right(90) 23 | turtle.forward(100) 24 | turtle.right(90) 25 | turtle.forward(100) 26 | 27 | turtle.mainloop() 28 | ``` 29 | 30 | ![正方形](D:\repository\PythonNotes\notes\第2章 Python基础\images\正方形.png) 31 | 32 | ## 画五星红旗(有难度,新手可跳过) 33 | 34 | ```python 35 | ''' 36 | 在开始绘制之前,我们要明白一点:不是随手画出的五星红旗都是国旗。在我国,国旗的形状、大小是有明确规定的,根据《中华人民共和国国家标准 国旗(GB 12982-2004)》, 37 | 这份标准明确记录了国旗的比例、颜色、每颗星的形状和位置等信息,为我们绘制国旗提供参考。 38 | 百度百科:https://baike.baidu.com/item/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%9B%BD%E6%97%97/240342 39 | ''' 40 | 41 | ''' 42 | 画五星红旗思路: 43 | 1.首先画红色背景 44 | 2.根据国旗制定标准计算出五角星坐标 45 | 大五角星:-175,145 46 | 第一个小五角星:-100,180 47 | 第二个小五角星:-85,150 48 | 第三个小五角星:-85,120 49 | 第四个小五角星:-100,-100 50 | 3.先画大五角星,再画小五角星 51 | 4.forward默认是朝东/右开始画,setheading可以调整初始朝向角度 52 | 5.turtle.screen()默认是(400, 300) 53 | ''' 54 | 55 | import turtle 56 | 57 | # 设置画图的速度 58 | turtle.speed(1) 59 | # 抬起笔,移动坐标,设定初始坐标 60 | turtle.up() 61 | turtle.goto(-200, 200) 62 | # 放下笔准备画 63 | turtle.down() 64 | # 准备填充颜色 65 | turtle.begin_fill() 66 | # 设置填充色和画笔的颜色 67 | turtle.fillcolor('red') 68 | turtle.pencolor('red') 69 | # 使用循环,循环两次画出一个矩形 70 | for i in range(2): 71 | turtle.forward(438) 72 | turtle.right(90) 73 | turtle.forward(292) 74 | turtle.right(90) 75 | turtle.end_fill() 76 | 77 | # 设置五角星颜色 78 | turtle.fillcolor('yellow') 79 | turtle.pencolor('yellow') 80 | 81 | # 画大五角星 82 | turtle.up() 83 | turtle.goto(-170, 145) 84 | turtle.down() 85 | turtle.begin_fill() 86 | for i in range(5): 87 | turtle.forward(50) 88 | turtle.right(144) 89 | turtle.end_fill() 90 | 91 | # 画第一颗小五角星 92 | turtle.up() 93 | turtle.goto(-100, 180) 94 | # 调整画第一条线的角度 95 | turtle.setheading(305) 96 | turtle.down() 97 | turtle.begin_fill() 98 | for i in range(5): 99 | turtle.forward(20) 100 | turtle.right(144) 101 | turtle.end_fill() 102 | 103 | # 画第二颗小五角星 104 | turtle.up() 105 | turtle.goto(-85, 150) 106 | turtle.setheading(30) 107 | turtle.down() 108 | turtle.begin_fill() 109 | for i in range(5): 110 | turtle.forward(20) 111 | turtle.right(144) 112 | turtle.end_fill() 113 | 114 | # 画第三颗小五角星 115 | turtle.up() 116 | turtle.goto(-85, 120) 117 | turtle.setheading(3) 118 | turtle.down() 119 | turtle.begin_fill() 120 | for i in range(5): 121 | turtle.forward(20) 122 | turtle.right(144) 123 | turtle.end_fill() 124 | 125 | # 画第四颗小五角星 126 | turtle.up() 127 | turtle.goto(-100, 100) 128 | turtle.setheading(300) 129 | turtle.down() 130 | turtle.begin_fill() 131 | for i in range(5): 132 | turtle.forward(20) 133 | turtle.right(144) 134 | turtle.end_fill() 135 | # 隐藏箭头 136 | turtle.hideturtle() 137 | turtle.done() 138 | 139 | turtle.mainloop() 140 | ``` 141 | 142 | ![五星红旗](D:\repository\PythonNotes\notes\第2章 Python基础\images\五星红旗.jpg) -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.4_注释.md: -------------------------------------------------------------------------------- 1 | # 注释 2 | 3 | 在写`Python`代码时,由于一个项目可能需要很久才能写完,或者一个项目需要和别人进行合作,所以为了能够更容易回忆自己以前写的代码功能,或者让合作者更容易理解自己写的代码,我们需要用注释来详细写清楚代码的用途。 4 | 5 | ```python 6 | # 单行注释 7 | 8 | ''' 9 | 多行 10 | 注释 11 | ''' 12 | 13 | """ 14 | 多行 15 | 注释 16 | """ 17 | 18 | def func(a, b): 19 | """ 20 | 函数注释:这个函数是用来计算a和b的和 21 | :param a: 第一个数据 22 | :param b: 第二个数据 23 | :return: 返回两个数之和 24 | """ 25 | return a + b 26 | 27 | print(func(2,3)) 28 | ``` 29 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.5_变量及数据类型.md: -------------------------------------------------------------------------------- 1 | # 变量及数据类型 2 | 3 | 4 | 5 | ## 变量 6 | 7 | 在程序设计中,变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。 8 | 9 | ```python 10 | a = 100 11 | b = 12.345 12 | c = 'hello, world' 13 | a, b, c = 1, 2, 3 14 | d = True 15 | e = 1 + 5j 16 | BI = 3.1415926 # 常量设置,大写,基本不去变动 17 | ``` 18 | 19 | 这里的`a, b, c, d, e`都是变量,我们把数据存到这些变量中。 20 | 21 | ### 变量的命名规则 22 | 23 | 对于每个变量我们需要给它取一个名字,就如同我们每个人都有属于自己的响亮的名字一样。在`Python`中,变量命名需要遵循以下这些必须遵守硬性规则和强烈建议遵守的非硬性规则。 24 | 25 | - 硬性规则: 26 | 27 | - 变量名由字母(广义的`Unicode`字符,不包括特殊字符)、数字和下划线构成,**数字不能开头**。 28 | - 大小写敏感(小写的`a`和大写的`A`是两个不同的变量)。 29 | - 不要跟关键字(有特殊含义的单词)和系统保留字(如函数、模块等的名字)冲突。 30 | - 不要太长,要有意义,不要用中文 31 | - 建议使用驼峰或下划线 32 | - 驼峰:`CarOfAlex` 33 | - 下划线:`car_of_alex` 34 | 35 | - PEP 8建议: 36 | 37 | - 用小写字母拼写,多个单词用下划线连接。 38 | 39 | - 受保护的实例属性用单个下划线开头(后面会讲到)。 40 | 41 | - 私有的实例属性用两个下划线开头(后面会讲到)。 42 | 43 | 44 | 45 | ## 数据类型 46 | 47 | 计算机能处理的数据有很多种类型,除了数值之外还可以处理文本、图形、音频、视频等各种各样的数据,那么不同的数据就需要定义不同的存储类型。`Python`中的数据类型很多,而且也允许我们自定义新的数据类型,我们先介绍几种常用的数据类型。 48 | 49 | ![数据类型](D:\repository\PythonNotes\notes\第2章 Python基础\images\数据类型.png) 50 | 51 | ### 数字类型 52 | 53 | 在`Python3`中,数字类型的数据包括整型`(int)`、浮点型`(float)`和复数型`(complex)`。 54 | 55 | 1. 整型 56 | 57 | `Python`中可以处理任意大小的整数(`Python 2.x`中有`int`和`long`两种类型的整数,但这种区分对`Python`来说意义不大,因此在`Python 3.x`中整数只有`int`这一种了),而且支持二进制(如`0b100`,换算成十进制是4)、八进制(如`0o100`,换算成十进制是64)、十进制(`100`)和十六进制(`0x100`,换算成十进制是256)的表示法。也可以使用代码来转换:`bin(二进制) oct(八进制) hex(十六进制)`。 58 | 59 | 2. 浮点型 60 | 61 | 浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如`123.456`)之外还支持科学计数法(如`1.23456e2`)。 62 | 63 | **注意:在计算机中,对于小数的计算是有误差的,所以`1.2 - 1.0 != 0.2`** 64 | 65 | 3. 复数型 66 | 67 | 复数型:形如`3+5j`,跟数学上的复数表示一样,唯一不同的是虚部的`i`换成了`j`。实际上,这个类型并不能算作常用类型,大家了解下就可以了。 68 | 69 | ### 字符串型`(str)` 70 | 71 | 字符串是以单引号或双引号括起来的任意文本,比如`'hello'`和`"hello"`,字符串还有原始字符串表示法、字节字符串表示法、`Unicode`字符串表示法,而且可以书写成多行的形式(用三个单引号或三个双引号开头,三个单引号或三个双引号结尾)。 72 | 73 | ### 布尔型`(bool)` 74 | 75 | 布尔值只有`True`、`False`两种值,要么是`True`,要么是`False`,在`Python`中,可以直接用`True`、`False`表示布尔值(请注意大小写),也可以通过布尔运算计算出来(例如`3 < 5`会产生布尔值`True`,而`2 == 1`会产生布尔值`False`)。 76 | 77 | ### 列表`(list)` 78 | 79 | ```python 80 | ls = ['zhangsan', 'lisi', 'wangwu'] 81 | ``` 82 | 83 | ### 字典`(dict)` 84 | 85 | ```python 86 | dic = {'name':'zhangsan', 'age':18} 87 | ``` 88 | 89 | ### 元组`tuple` 90 | 91 | ```python 92 | tup = (1, 2, 3, 4) 93 | ``` 94 | 95 | ### 集合`(set)` 96 | 97 | ```python 98 | se = {'zhangsan', 'lisi', 'wangwu'} 99 | ``` 100 | 101 | ## 查看变量类型 102 | 103 | ```python 104 | # 变量赋值 105 | a = 100 106 | b = 12.345 107 | c = 'hello, world' 108 | d = True 109 | e = 1 + 5j 110 | f, g = 1, 3 # 多变量赋值 111 | 112 | # 打印变量的类型,type为内置函数 113 | print(type(a)) 114 | print(type(b)) 115 | print(type(c)) 116 | print(type(d)) 117 | print(type(e)) 118 | print(e.real) # 输出实数部分 119 | print(e.imag) # 输出虚数部分 120 | ``` 121 | 122 | `f, g = 1, 3`赋值其实是一种拆包,拆包前后变量的数量要一致。也可以采用`*`这种方式来避免,如:``o, *p, q = 1, 2, 3, 4, 5`,其中`*p = [2, 3]` 123 | 124 | 125 | 126 | ## 数据类型转换 127 | 128 | - `int()`:将一个数值或字符串转换成整数,可以指定进制。 129 | - 可以进行`+,-,*,/,%(取余),//(取整)`运算 130 | - `float()`:将一个字符串转换成浮点数。 131 | - 计算机里的小数都是模糊计数,会有误差 132 | - `str()`:将指定的对象转换成字符串形式,可以指定编码。 133 | - 用单引号,双引号或者三引号 134 | - 三引号可以多行写字符串,多行注释内容 135 | - 字符长可以进行的操作:`+,*` 136 | - 乘法是字符串乘数字 137 | - `chr()`:将整数转换成该`ASCII`编码对应的字符串(数值-->字符)。 138 | - `ord()`:将字符串(一个字符)转换成`ASCII`对应的编码(字符-->数值)。 139 | - `list()`:将序列转换成列表 140 | - `tuple()`:将序列转换为元组 141 | - `eval()`:转换为有效的`Python`表达式,并返回该对象 142 | 143 | ```python 144 | a = 100 145 | b = 's' 146 | c = (1, 2, 3) 147 | d = '1.1' 148 | 149 | # 通过内置函数对数据类型进行转换 150 | print(int(a)) 151 | print(float(a)) 152 | print(str(a)) 153 | print(chr(a)) 154 | print(ord(b)) 155 | print(list(c)) 156 | print(tuple(c)) 157 | print(eval(d)) 158 | ``` 159 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.6_输入、输出和格式化输出.md: -------------------------------------------------------------------------------- 1 | # 输入、输出、格式化输出 2 | 3 | 4 | 5 | ## 输入 6 | 7 | 使用`input`读取用户需要输入的内容,将其转换为`string(字符串)`类型并返回,`input`的参数可有可无,如果有参数的话,会输出参数的内容,不换行。通常情况下我们在输入一些数据,然后敲击回车,就完成了本次输入。 8 | 9 | ```python 10 | name = input("Enter your name: ") 11 | print(name) 12 | ``` 13 | 14 | **这里要注意的是,`input`返回的是`string`类型,如果想输入数字,还需要进行类型转换**,例如 15 | 16 | ```python 17 | num = int(input("Enter a number: ")) 18 | print(num*2) 19 | ``` 20 | 21 | 其实以上这种转换并不安全,因为如果user输入字符串的话,没法转为`int`类型,这样程序就会出错,异常终止。所以一种比较简单的方法是,**先对输出进行判断,然后再转换**,因为还没有说到判断语句,所以这个判断之后再说。 22 | 23 | 24 | 25 | ## 输出 26 | 27 | 一般在控制台中我们用`print`进行输出,因为比较简单,所以之前也一直在使用。`print`的原型如下 28 | 29 | ```python 30 | print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) 31 | ``` 32 | 33 | >补充内容:转义字符 34 | > 35 | >1. `\n` 换行 36 | >2. `\t` 制表符,也称补充符,**补充四个空格,并不代表一定是四个空格** 37 | >3. `\b`退格 38 | >4. `\r`替换 39 | >5. `\\`代表斜杠本身 40 | >6. `r'哈哈\t'`原子符,字符串中的转义符不起作用,只代表字符串 41 | 42 | 看起来很复杂,但是这个参数都是有默认参数的,我们可以先简单使用前三个参数,后面的默认即可。 43 | 44 | ```python 45 | print(*objects, sep=' ', end='\n') 46 | ``` 47 | 48 | 第一个参数是我们要在控制台输出的数据,可以是多个,用`,`逗号隔开,`python`的`print`很强大,可以输出很多种数据类型,只要你觉的可以输出的,`print`都可以输出,你觉得不能输出的,试一试也可能输出。 49 | 50 | ```python 51 | print("xx") 52 | print(1) 53 | print(True) 54 | print(None) 55 | ``` 56 | 57 | `sep`用来将多个数据隔开,默认是空格,`end`加在输出的末尾,默认是换行符 58 | 59 | ```python 60 | print(1,2,3,sep='@@',end='<>\n') 61 | #用@@分隔数据,结尾加上<>并换行 62 | ``` 63 | 64 | 65 | 66 | ## 格式化输出 67 | 68 | ### 占位符 69 | 70 | 如何格式化输出字符串呢,例如`你好XX,你的额度是xx`,其中`xx`的变量,我们无法预知,这个时候就需要格式化输出,和`C语言`一样,我们可以使用占位符`%?`,其中`?`代表不同的字符,例如`%s`代表字符串,`%d`代表十进制整数,`%f`代表浮点数,例如 71 | 72 | ```python 73 | name = "Potato" 74 | b = 100 75 | print("你好%s,你的额度是%d" % (name,b) ) 76 | #name将替换%s的位置,b将替换%d的位置,字符串后的%用来说明是哪些变量要替换前面的占位符,当只有一个变量的时候,可以省略括号 77 | ``` 78 | 79 | 占位符还可以控制输出的格式,例如保留几位小数,填充前导0等,以下是例子 80 | 81 | ```python 82 | print("小数: %.2f" % 3.14159)# %.2f代表保留两位小数 83 | print("小数: %.2f" % 4.5)# %.2f保留两位小数,不够的位用0补充 84 | print("占位: %3d" % 5)# %3d代表这个数的宽度为3,不够的话用空格在前面补,如果数的宽度大于3,则正常输出 85 | print("前导0: %05d" % 2)# %05d代表这个数的宽度为5,不够的话用0在前面补,如果数的宽度大于5,则正常输出 86 | print('百分位数:%.2f%%' % 3.2345) 87 | ``` 88 | 89 | **如果不知道数据类型的话,用`%s`即转为字符串进行输出会比较稳妥**,还有许多种占位符的格式,具体使用时可以搜索,一般常用的就是以上那些。 90 | 91 | 92 | 93 | ### format 94 | 95 | 可以利用`string`对象的`format`方法,进行格式化,以下是例子 96 | 97 | ```python 98 | print("你好{0},你的余额是{1:.2f}".format("Potato",3.1)) 99 | #{0}代表占位符和format里的参数对应,{1:.2f},冒号后是格式控制,代表保留两位小数 100 | ``` 101 | 102 | 这种方式使用起来可能不是很方便。或者还可以使用`py`内置的`format`函数,例如 103 | 104 | ```python 105 | print(format(3.1415,".2f")) 106 | #结果是3.14 107 | ``` 108 | 109 | 110 | 111 | ### 第三种格式化输出,这种方法较为常用 112 | 113 | `Python3.6`及之后的版本可以用 114 | 115 | ```python 116 | name = "Potato" 117 | b = 100 118 | print(f"你好{name},你的额度是{b}") 119 | ``` 120 | 121 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.7_运算符.md: -------------------------------------------------------------------------------- 1 | # 运算符 2 | 3 | `Python`支持多种运算符,下表大致按照优先级从高到低的顺序列出了所有的运算符,运算符的优先级指的是多个运算符同时出现时,先做什么运算然后再做什么运算。主要包括:算术运算符、赋值运算符、比较运算符、逻辑运算符和位运算符。 4 | 5 | | 运算符 | 描述 | 6 | | ------------------------------------------------------------ | ------------------------------ | 7 | | `[]` `[:]` | 下标,切片 | 8 | | `**` | 指数 | 9 | | `~` `+` `-` | 按位取反, 正负号 | 10 | | `*` `/` `%` `//` | 乘,除,取余,取整 | 11 | | `+` `-` | 加,减 | 12 | | `>>` `<<` | 右移,左移 | 13 | | `^` `\|` | 按位异或,按位或 | 14 | | `<=` `<` `>` `>=` | 小于等于,小于,大于,大于等于 | 15 | | `==` `!=` | 等于,不等于 | 16 | | `is` `is not` | 身份运算符 | 17 | | `in` `not in` | 成员运算符 | 18 | | `not` `or` `and` | 逻辑运算符 | 19 | | `=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` `|=` `^=` `>>=` `<<=` | (复合)赋值运算符 | 20 | 21 | `not > and > or` **在开发中,最好使用括号来说明运算的优先级。** 22 | 23 | ```python 24 | print(True or True and False) # True 25 | ``` 26 | 27 | 按位运算是特殊的运算方法,具体算法可以百度。整型除法运算会得到浮点型数据。 28 | 29 | 下面的例子演示了赋值运算符和复合赋值运算符的使用。 30 | 31 | ```Python 32 | a = 10 33 | b = 3 34 | c, d = 2, 3 # 多变量赋值 35 | a += b # 相当于:a = a + b 36 | a *= a + 2 # 相当于:a = a * (a + 2) 先算右边的表达式 37 | print(a) # 想想这里会输出什么 38 | ``` 39 | 40 | 下面的例子演示了比较运算符(关系运算符)、逻辑运算符和身份运算符的使用。 41 | 42 | ```Python 43 | flag0 = 1 == 1 44 | flag1 = 3 > 2 45 | flag2 = 2 < 1 46 | flag3 = flag1 and flag2 47 | flag4 = flag1 or flag2 48 | flag5 = not (1 != 2) 49 | print('flag0 =', flag0) # flag0 = True 50 | print('flag1 =', flag1) # flag1 = True 51 | print('flag2 =', flag2) # flag2 = False 52 | print('flag3 =', flag3) # flag3 = False 53 | print('flag4 =', flag4) # flag4 = True 54 | print('flag5 =', flag5) # flag5 = False 55 | print(flag1 is True) # True 56 | print(flag2 is not False) # False 57 | print(a and 5 and 0 and 'hell0') 58 | print('good' and 'yes' and 'od') 59 | print(0 or [] or 'lisi' or 5) 60 | print(0 or [] or ()) 61 | ``` 62 | 63 | 在逻辑运算符中:`and`运算时,当前面为False时就不执行后面,当前面为True时,会执行后面,如果后面正确则会打印,当都不为0时,取最后一个数字;`or`运算时,当前面正确时整体为True,就不会运算后面,当前面为False时,会运算后面,后面为True时打印,不正确时不打印,打印时取第一个不为0数字。 64 | 65 | 下面是位运算的使用。 66 | 67 | ```python 68 | color = 0xF0384E 69 | red = color >> 16 70 | green = color >> 8 & 0xFF 71 | blue = color & 0xFF 72 | print(hex(red), hex(green), hex(blue)) 73 | ``` 74 | 75 | #### 练习:输入年份判断是不是闰年 76 | 77 | > 闰年说明:四年一闰,百年不闰;400年再闰 78 | 79 | ```Python 80 | year = int(input('请输入年份:')) 81 | is_leap = (year % 4 == 0 and year % 100 != 0) or year % 400 == 0 82 | print(is_leap) 83 | ``` 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.1_Python基础/2.1.8_字符串.md: -------------------------------------------------------------------------------- 1 | # 字符串 2 | 3 | --- 4 | 5 | 第二次世界大战促使了现代电子计算机的诞生,最初计算机被应用于导弹弹道的计算,而在计算机诞生后的很多年时间里,计算机处理的信息基本上都是数值型的信息。世界上的第一台电子计算机叫`ENIAC`(电子数值积分计算机),诞生于美国的宾夕法尼亚大学,每秒钟能够完成约5000次浮点运算。随着时间的推移,虽然数值运算仍然是计算机日常工作中最为重要的事情之一,但是今天的计算机处理得更多的数据可能都是以文本的方式存在的,如果我们希望通过`Python`程序操作本这些文本信息,就必须要先了解字符串类型以及与它相关的知识。 6 | 7 | 所谓**字符串**,就是由零个或多个字符组成的有限序列。在`Python`程序中,如果我们把单个或多个字符用单引号或者双引号包围起来,就可以表示一个字符串。字符串是不可变的数据类型,对于字符串的任何操作,都不会改变原有的字符串。 8 | 9 | ```Python 10 | s1 = 'hello, world!' 11 | s2 = "hello, world!" 12 | # 以三个双引号或单引号开头的字符串可以换行,或者用于注释 13 | s3 = """ 14 | hello, 15 | world! 16 | """ 17 | print(s1, s2, s3, end='') 18 | ``` 19 | 20 | >可以在字符串中使用`\`(反斜杠)来表示**转义**,也就是说`\`后面的字符不再是它原来的意义,例如:`\n`不是代表反斜杠和字符n,而是表示换行;而`\t`也不是代表反斜杠和字符t,而是表示制表符。所以如果想在字符串中表示`'`要写成`\'`,同理想表示`\`要写成`\\`。 21 | 22 | ```Python 23 | s1 = '\'hello, world!\'' 24 | s2 = '\n\\hello, world!\\\n' 25 | print(s1, s2, end='') 26 | ``` 27 | 28 | 在`\`后面还可以跟一个八进制或者十六进制数来表示字符,例如`\141`和`\x61`都代表小写字母`a`,前者是八进制的表示法,后者是十六进制的表示法。也可以在`\`后面跟Unicode字符编码来表示字符,例如`\u9a86\u660a`代表的是中文“骆昊”。运行下面的代码,看看输出了什么。 29 | 30 | ```Python 31 | s1 = '\141\142\143\x61\x62\x63' 32 | s2 = '\u9a86\u660a' 33 | print(s1, s2) 34 | ``` 35 | 36 | 如果不希望字符串中的`\`表示转义,我们可以通过在字符串的最前面加上字母`r`来加以说明,再看看下面的代码又会输出什么。 37 | 38 | ```Python 39 | s1 = r'\'hello, world!\'' 40 | s2 = r'\n\\hello, world!\\\n' 41 | print(s1, s2, end='') 42 | ``` 43 | 44 | `Python`为字符串类型提供了非常丰富的运算符,我们可以使用`+`运算符来实现字符串的拼接,可以使用`*`运算符来重复一个字符串的内容,可以使用`in`和`not in`来判断一个字符串是否包含另外一个字符串(成员运算),我们也可以用`[]`和`[:]`运算符从字符串取出某个字符或某些字符(切片运算),切片会生成一个新的字符串,代码如下所示。 45 | 46 | 切片时,无论是正向选取,还是逆向选取,选取的范围方向与步长方向需要保持一致 47 | 48 | `str[1:5:2]` 或者 `srt[-1:-5:-1]` 49 | 50 | ```Python 51 | s1 = 'hello ' * 3 52 | print(s1) 53 | s2 = 'world' 54 | s1 += s2 55 | print(s1) 56 | print('ll' in s1) 57 | print('good' in s1) 58 | str2 = 'abc123456' 59 | # 从字符串中取出指定位置的字符(下标运算) 60 | print(str2[2]) # c python中索引-是从0开始 61 | # 字符串切片(从指定的开始索引到指定的结束索引) 62 | # [x:y:z] x表示开始索引,y表示结束索引,z代表间隔长度 63 | print(str2[2:5]) 64 | print(str2[2:]) 65 | print(str2[2::2]) 66 | print(str2[::2]) 67 | print(str2[::-1]) 68 | print(str2[-3:-1]) 69 | ``` 70 | 71 | 在`Python`中,我们还可以通过一系列的方法来完成对字符串的处理,代码如下所示。 72 | 73 | ```Python 74 | str1 = 'hello, world!' 75 | # 通过内置函数len计算字符串的长度 76 | print(len(str1)) 77 | # 获得字符串首字母大写的拷贝 78 | print(str1.capitalize()) 79 | # 获得字符串每个单词首字母大写的拷贝 80 | print(str1.title()) 81 | # 获得字符串变大写后的拷贝 82 | print(str1.upper()) 83 | # 从字符串中查找第一个子串所在位置 84 | print(str1.find('or')) 85 | print(str1.find('shit')) 86 | # 与find类似但找不到子串时会引发异常,find返回为-1,index会报错 87 | print(str1.index('or')) 88 | print(str1.index('shit')) 89 | # 从字符串计算子串出现次数 90 | print(str1.count('o')) 91 | # 检查字符串是否以指定的字符串开头 92 | print(str1.startswith('He')) 93 | print(str1.startswith('hel')) 94 | # 检查字符串是否以指定的字符串结尾 95 | print(str1.endswith('!')) 96 | # 将字符串以指定的宽度居中并在两侧填充指定的字符 97 | print(str1.center(50, '*')) 98 | # 将字符串以指定的宽度靠右放置左侧填充指定的字符 99 | print(str1.rjust(50, ' ')) 100 | # 让字符串以指定长度显示,长度不够默认用空格补齐 101 | print('Monday'.ljust(30, '+')) 102 | str2 = 'abc123456' 103 | # 检查字符串是否由数字构成 104 | print(str2.isdigit()) 105 | # 检查字符串是否以字母构成 106 | print(str2.isalpha()) 107 | # 检查字符串是否以数字和字母构成 108 | print(str2.isalnum()) 109 | str3 = ' jackfrued@126.com ' 110 | print(str3) 111 | # 获得字符串修剪左右两侧空格之后的拷贝 112 | print(str3.strip()) 113 | # 替换字符串时,注意原来的字符串不会变,有返回值,所以要赋值 114 | str2 = str1.replace('l', 'x') 115 | print(str2) 116 | # 分割字符串,返回的是列表 117 | # partition 按某个字符分割为三部分,保留分隔符,返回的是元组 118 | str2 = str1.split(' ') 119 | # 以固定格式拼接字符串 120 | fruits = ['apple', 'pear', 'peache'] 121 | print('-'.join(fruits)) 122 | ``` 123 | 124 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.10_map()映射函数.md: -------------------------------------------------------------------------------- 1 | # `map()`映射函数 2 | 3 | --- 4 | 5 | 分而治之`map(func1, map(func2, map(func3, lst)))` 6 | 7 | ```python 8 | # 计算列表中每个数字的平方 9 | lst = [1, 4, 7, 2, 5, 8] 10 | 11 | def func(el): 12 | return el**2 13 | m = map(func, lst) 14 | n = lambda el: el ** 2, lst 15 | print(list(m)) 16 | print(list(n)) 17 | ``` 18 | 19 | ```python 20 | lst1 = [1, 3, 5, 7, 9] 21 | lst2 = [2, 4, 6, 8, 10] 22 | m = map(lambda x, y, z: x + y, lst1, lst2, [2,1,3,4,5]) # 这里也有水桶效应 23 | print(list(m)) 24 | ``` 25 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.11_reduce()函数.md: -------------------------------------------------------------------------------- 1 | # reduce()函数 2 | 3 | --- 4 | 5 | reduce()函数会对参数序列中的元素进行累积。`reduce(function,iterable)` 6 | 7 | ```python 8 | from functools import reduce 9 | data = [1,2,3,4] 10 | func = lambda x,y: x + y 11 | r = reduce(func,data) 12 | print(r) 13 | ``` 14 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.12_常用内置函数.md: -------------------------------------------------------------------------------- 1 | # 常用内置函数 2 | 3 | --- 4 | 5 | 什么是内置函数?就是`python`给你提供的,拿来直接用的函数。一共提供了68个内置函数,内置函数会不断增加。 6 | 7 | ## 迭代器相关`iter/next/range` 8 | 9 | ```python 10 | lst = ['白蛇传', '枯落潭', '庄周闲游'] 11 | it = iter(lst) 12 | print(it.__next__()) # 白蛇传 13 | print(next(it)) # 枯落潭 14 | ``` 15 | 16 | ## 内存相关`hash` 17 | 18 | 可哈希意味着元素不能重复,计算出的存储地址的值是唯一不变的。字典是可哈希的,因为字典的键都是不重复的。 19 | 20 | ![hash讲解](D:\repository\PythonNotes\notes\第3章 Python语法\images\hash讲解.png) 21 | 22 | ## zip 23 | 24 | 满足水桶效应,多余的值会自动去掉 25 | 26 | ```python 27 | list1 = [1, 2, 3, 4, 5] 28 | list2 = [5, 6, 7, 8] 29 | list3 = [9, 10, 11, 12] 30 | a = zip(list1, list2, list3) 31 | print(a) # 32 | for el in a: # 打印内容,是元组 33 | print(el) 34 | ''' 35 | (1, 5, 9) 36 | (2, 6, 10) 37 | (3, 7, 11) 38 | (4, 8, 12) 39 | ''' 40 | ``` 41 | 42 | ## eval 43 | 44 | `json`格式还原为字典 45 | 46 | ```python 47 | s = '5+6' 48 | ret = eval(s) 49 | print(ret) # 11 50 | ``` 51 | 52 | ## exec 53 | 54 | ```python 55 | content = input('请输入你的代码:') 56 | exec(content) 57 | ``` 58 | 59 | ```python 60 | s = "a = 10" 61 | exec(s) 62 | # pycharm在这里会报错,但是代码是对的 63 | print(a) # 10 64 | ``` 65 | 66 | ## compile 67 | 68 | ```python 69 | s = 'for i in range(10): print(i)' 70 | c = compile(s, '', 'exec') # 中间一定要加'' 71 | exec(c) 72 | 73 | s = '5+9' 74 | c = compile(s, '', 'eval') 75 | ret = eval(c) 76 | print(ret) 77 | 78 | s = "content = input('请输入你的名字:')" 79 | c = compile(s,'','single') 80 | exec(c) 81 | print(content) 82 | ``` 83 | 84 | ## repr 85 | 86 | ```python 87 | print('你好。我叫周润发') # 对用户友好 88 | print(repr('你好。我叫周润发')) # 程序中存储的内容 89 | print(r'\n,\t.had哈儿') # 原样输出 90 | print('我叫%r' % '周润发') # 原样输出,带单引号 91 | ``` 92 | 93 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.13_内置函数作业.md: -------------------------------------------------------------------------------- 1 | # 内置函数作业 2 | 3 | --- 4 | 5 | 1. 给列表每个元素加`_sb` 6 | 7 | ```python 8 | name = ['oldboy', 'alex', 'wusir'] 9 | print(list(map(lambda x: x + '_sb', name))) 10 | ``` 11 | 12 | 2. 给字典的值加`sb` 13 | 14 | ```python 15 | l = [{'name':'alex'},{'name':'y'}] 16 | print(list(map(lambda x: x['name'] + 'sb', l))) 17 | ``` 18 | 19 | 3. 筛选值大于20 20 | 21 | ```python 22 | shares = { 23 | 'IBM':36.6, 24 | 'Lenovo':23.2, 25 | 'odlboy':21.2, 26 | 'ocean':10.2, 27 | } 28 | 29 | print(list(filter(lambda x:shares[x] > 20, shares))) 30 | ``` 31 | 32 | 4. 计算份额乘以股价 33 | 34 | ```python 35 | portfolio = [ 36 | {'name':'IBM','shares':100,'price':91.1}, 37 | {'name':'APPL','shares':50,'price':543.22}, 38 | {'name':'FB','shares':200,'price':21.09}, 39 | {'name':'HPQ','shares':35,'price':31.75}, 40 | {'name':'YHOO','shares':45,'price':16.35}, 41 | {'name':'ACNE','shares':75,'price':115.65} 42 | ] 43 | print(list(map(lambda x:x['shares'] * x['price'], portfolio))) 44 | ``` 45 | 46 | 5. 计算股价大于100 47 | 48 | ```python 49 | portfolio = [ 50 | {'name':'IBM','shares':100,'price':91.1}, 51 | {'name':'APPL','shares':50,'price':543.22}, 52 | {'name':'FB','shares':200,'price':21.09}, 53 | {'name':'HPQ','shares':35,'price':31.75}, 54 | {'name':'YHOO','shares':45,'price':16.35}, 55 | {'name':'ACNE','shares':75,'price':115.65} 56 | ] 57 | print(list(filter(lambda x:x['price'] > 100, portfolio))) 58 | ``` 59 | 60 | 6. 筛选第一项大于二,第三项大于三 61 | 62 | ```python 63 | l1 = [1,2,3,4,5,6] 64 | l2 = ['oldboy','alex','wusir','太白','日天'] 65 | tu = ('**','***','****','*****') 66 | print(list(filter(lambda x:x[0] > 2 and len(x[2]) > 3, zip(l1,l2,tu)))) 67 | ``` 68 | 69 | 7. 按值从小到大排序 70 | 71 | ```python 72 | l1 = [ 73 | {'sales_volum':0}, 74 | {'sales_volum':337}, 75 | {'sales_volum':475}, 76 | {'sales_volum':396}, 77 | {'sales_volum':172}, 78 | {'sales_volum':9}, 79 | {'sales_volum':58}, 80 | {'sales_volum':272}, 81 | {'sales_volum':456}, 82 | {'sales_volum':440}, 83 | {'sales_volum':239}, 84 | {'sales_volum':108} 85 | ] 86 | print(sorted(l1, key=lambda x:x['sales_volum'])) 87 | ``` 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.14_二分查找.md: -------------------------------------------------------------------------------- 1 | # 二分查找 2 | 3 | --- 4 | 5 | 必须是有序查找才能用,所以在用的时候可以先对数据进行排序 6 | 7 | ```python 8 | lst = [11,22,33,44,55,66,77,88,99,111,222,333,444,555] 9 | left = 0 10 | right = len(lst) - 1 11 | n = 66 12 | while left <= right: # 当右边比左边小时推出循环 13 | mid = (left + right)//2 # 索引没有小数 14 | if lst[mid] > n: 15 | right = mid - 1 16 | if lst[mid] < n: 17 | left = mid + 1 18 | if lst[mid] == n: 19 | print('找到了') 20 | break 21 | else: 22 | print('没有这个数') 23 | ``` 24 | 25 | ```python 26 | # 递归来做二分法 27 | lst = [11,22,33,44,55,66,77,88,99,111,222,333,444,555] 28 | def func(n, left, right): 29 | if left <= right: 30 | mid = (left + right)//2 31 | if n > lst[mid]: 32 | left = mid + 1 33 | return func(n, left, right) # 深坑,函数值返回给调用者 34 | if n < lst[mid]: 35 | right = mid - 1 36 | return func(n, left, right) 37 | if n == lst[mid]: 38 | print('找到了') 39 | return mid # 递归只能通过return终止回归 40 | else: 41 | print('没有这个数') 42 | return -1 43 | 44 | func(66, 0, len(lst)-1) 45 | ``` 46 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.1_函数、返回值和参数.md: -------------------------------------------------------------------------------- 1 | # 函数、返回值和参数 2 | 3 | --- 4 | 5 | ## 函数 6 | 7 | 函数的目的是方便重复使用相同的一段代码。将一些操作隶属于一个函数,再想实现相同操作的时候,只用调用该函数名即可,而不需要重复编写所有的语句。**函数也是一个特殊对象,可以赋值给其他变量使用。** 8 | 9 | ```python 10 | # 语法 11 | def yue(形参): # 写函数 12 | print('打开默默') 13 | print('搜索') 14 | print('出发') 15 | return '10086' 16 | 17 | ret = yue(实参) # 调用函数 18 | ``` 19 | 20 | ## 函数的返回值 21 | 22 | - `return`:在函数执行时,遇到直接返回 23 | - 如果函数什么都不写,不写`return`,没有返回值,得到`None` 24 | - `return`可以终止一个函数的执行 25 | - 在函数中间或者末尾只写`return`,返回`None` 26 | - 在函数中可以返回多个返回值,`return 返回值1 返回值2`,多个返回值接收到的是**元组,元组不可变所以安全** 27 | 28 | ```python 29 | def sum(): 30 | a = int(input('请输入一个a:')) 31 | b = int(input('请输入一个b:')) 32 | c = a + b 33 | return c 34 | 35 | ret = sum() 36 | print(ret) 37 | print(type(ret)) 38 | ``` 39 | 40 | ## 函数的参数 41 | 42 | ```python 43 | def yue(tools): # 添加形参 44 | print('打开%s' % tools) 45 | print('搜索') 46 | print('出发') 47 | return '10086' 48 | 49 | ret = yue('探探') # 添加实参 50 | ``` 51 | 52 | 函数执行的时候给函数传递信息;形参:函数声明的位置的变量;实参:函数调用的时候给的具体值;传参:把实参交给形参的过程。 53 | 54 | ### 实参 55 | 56 | 1. 位置参数:按照形参的位置传参,当函数参数很多事,必须记住每一个位置是什么 57 | 58 | ```python 59 | def chi(good_food, no_good_food, drink, ice_cream): 60 | print(good_food, no_good_food, drink, ice_cream) 61 | 62 | chi('法国蜗牛', '卫龙', '大白梨', '哈根达斯') # 按照位置传参 63 | ``` 64 | 65 | 2. 关键字参数:按照形参的名字传参 66 | 67 | ```python 68 | def chi(good_food, no_good_food, drink, ice_cream): 69 | print(good_food, no_good_food, drink, ice_cream) 70 | 71 | chi(drink='神仙水', ice_cream='老冰棍', good_food='盖浇饭', no_good_foof='锅包肉') 72 | ``` 73 | 74 | 3. 混合参数:位置和关键字参数一起用,顺序:先位置参数,再关键字参数 75 | 76 | ```python 77 | def chi(good_food, no_good_food, drink, ice_cream): 78 | print(good_food, no_good_food, drink, ice_cream) 79 | 80 | chi('盖浇饭', '锅包肉', ice_cream='老冰棍', drink='大白梨') 81 | ``` 82 | 83 | ### 形参 84 | 85 | 1. 位置参数 86 | 87 | ```python 88 | def chi(good_food, no_good_food, drink, ice_cream): # 位置形参 89 | print(good_food, no_good_food, drink, ice_cream) 90 | 91 | chi('盖浇饭', '锅包肉', ice_cream='老冰棍', drink='大白梨') 92 | ``` 93 | 94 | 2. 默认值参数:默认值参数必须在最后 95 | 96 | ```python 97 | def regist(name, phone, gerder='男'): 98 | print(name, phon, gender) 99 | 100 | regist('阿凡达', '10086') 101 | regist('阿凡提', '10081') 102 | regist('女神', '10089', '女') 103 | ``` 104 | 105 | 3. 动态参数 106 | 107 | 表示接收位置参数的动态传参,接收到的是元组,动态传参不传参数也可以,以上参数可以随意搭配,但是顺序不能乱。 108 | 109 | 顺序:位置参数 --> `*args(arguments)` --> 默认值参数 --> `**kwargs` 110 | 111 | ```python 112 | def chi(name, *food, location='北京'): # 表示接收位置参数的动态传参,接收到的是元组 113 | print(name + '在' + location + '吃'+str(food)) # 这里的food是元组,不能喝字符串直接相加 114 | 115 | chi('太白','狗不理') 116 | ``` 117 | 118 | ```python 119 | # 关键字动态传参 120 | def chi(*food1, **food): # 可以接收所有类型参数 121 | print(food) 122 | 123 | chi('tq1258', good_food='狗不理', no_good_food='汉堡', drink='大白梨') 124 | ``` 125 | 126 | ## 作业 127 | 128 | 1. 写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者 129 | 130 | ```python 131 | list1 = ['皇阿玛', '纯妃', '贵妃', '脾肺', '咖啡'] 132 | def func(lst): 133 | result = [] 134 | for i in range(len(list)): 135 | if i%2 == 1: 136 | result.append(list[i]) 137 | return result 138 | 139 | ret = func(list1) 140 | print(ret) 141 | ``` 142 | 143 | ```python 144 | list1 = ['皇阿玛', '纯妃', '贵妃', '脾肺', '咖啡'] 145 | def func(lst): 146 | return lst[1::2] # 从第一个开始,每个两个取一个 147 | 148 | print(func(list1)) 149 | ``` 150 | 151 | 2. 写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于2 152 | 153 | ```python 154 | def func(a): 155 | return len(a) > 5 156 | 157 | print(func('我喜欢python')) 158 | ``` 159 | 160 | 3. 写函数,检查传入列表的长度,如果大于2,将列表的前两项内容返回给调用者 161 | 162 | ```python 163 | def func(a): 164 | if len(a) > 2: 165 | return a[0:2] 166 | 167 | print(func([2,3,4])) 168 | ``` 169 | 170 | 4. 写函数,计算传入函数的字符串中,数字、字母、空格以及其他内容的个数,并返回结果 171 | 172 | ```python 173 | def func(a): 174 | num = 0 175 | alpha = 0 176 | space = 0 177 | other = 0 178 | for i in a: 179 | if i.isdigit(): 180 | num += 1 181 | elif i.isalpha(): # 不能判断中文 182 | alpha += 1 183 | elif i == ' ': 184 | space += 1 185 | else: 186 | other += 1 187 | return num alpha space other 188 | 189 | print(func('dfdsdfhew2342 323%%')) 190 | ``` 191 | 192 | 5. 写函数,接收两个数字参数,返回较大的数 193 | 194 | ```python 195 | def func(a, b): 196 | return a if a > b else b # 三元运算符,适合两个参数 197 | 198 | print(func(10, 20)) 199 | ``` 200 | 201 | 6. 写函数,检查传入字典的每一个`value`的长度,如果大于2,保留前两个长度的内容,并将新内容返回 202 | 203 | ```python 204 | dic = {'k1':'v1v1', 'k2':11, 'k3':22} 205 | def func(dic): 206 | newdic = {} 207 | for k,v in dic.items(): 208 | if len(v) > 2: 209 | s = v[0:2] 210 | newdic[k] = s 211 | else: 212 | newdic[k] = v 213 | return newdic 214 | 215 | print(func(dic)) 216 | ``` 217 | 218 | 7. 写函数,此函数只接收一个参数且是列表,返回字典,字典的键值对为列表索引和对应元素 219 | 220 | ```python 221 | lst = [11,22,33] 222 | def func(lst): 223 | dic = {} 224 | if type(lst) == list: 225 | for i in range(len(lst)): 226 | dic[i+1] = lst[i] 227 | return dic 228 | else: 229 | return '不是列表' 230 | 231 | print(func(lst)) 232 | ``` 233 | 234 | 8. 写函数,函数接收四个参数:姓名,性别,年龄,学历。将内容追加到`student`文件 235 | 236 | ```python 237 | def func(name, gender, age, edu): 238 | with open('student.txt', mode='a', encoding='utf-8') as f: 239 | f.write(name+'_'+gender+'_'+age+'_'+edu+'\n') 240 | 241 | name = input('请输入名字:') 242 | gender = input('请输入性别:') 243 | age = input('请输入年龄:') 244 | edu = input('请输入学历:') 245 | print(func(name, gender, age, edu)) 246 | ``` 247 | 248 | 9. 支持用户持续输入,`Q/q`退出,性别默认男,如果是女生,性别输入女 249 | 250 | ```python 251 | def func(name, age, edu, gender='男'): 252 | with open('student.txt', mode='a', encoding='utf-8') as f: 253 | f.write(name+'_'+gender+'_'+age+'_'+edu+'\n') 254 | 255 | while 1: 256 | content = input('是否输入学生信息(输入Q/q退出):') 257 | if content.upper() == 'Q': 258 | break 259 | else: 260 | name = input('请输入名字:') 261 | gender = input('请输入性别:') 262 | age = input('请输入年龄:') 263 | edu = input('请输入学历:') 264 | if gender == '': 265 | func(name, age, edu) 266 | else: 267 | func(name, age, edu, gender) 268 | ``` 269 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.2_函数的说明文档.md: -------------------------------------------------------------------------------- 1 | # 函数的说明文档 2 | 3 | --- 4 | 5 | 语法:`help(函数)` 6 | 7 | ![函数定义说明文档](D:\repository\PythonNotes\notes\第3章 Python语法\images\函数定义说明文档.png) 8 | 9 | ```python 10 | def summ(a, b): 11 | ''' 12 | 求和函数 13 | :param a: 14 | :param b: 15 | :return: 16 | ''' 17 | return a + b 18 | 19 | help(summ) 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.3_函数嵌套和作用域.md: -------------------------------------------------------------------------------- 1 | # 函数嵌套和作用域 2 | 3 | --- 4 | 5 | ## 函数的嵌套 6 | 7 | 1. 函数可以无限的嵌套 8 | 9 | ```python 10 | def outer(): 11 | print('哈哈') 12 | def inner(): 13 | print('呵呵') 14 | inner() 15 | outer() 16 | ``` 17 | 18 | ```python 19 | def outer(): 20 | print('哈哈') 21 | def inner_1(): 22 | print('呵呵') 23 | def inner_1_1(): 24 | print('嘻嘻') 25 | inner_1_1() 26 | print('吼吼') 27 | def inner_2(): 28 | print('嘿嘿') 29 | inner_2() 30 | inner_1() 31 | outer() 32 | 33 | # 结果 34 | 哈哈,嘿嘿,呵呵,嘻嘻,吼吼 35 | ``` 36 | 37 | ## 作用域 38 | 39 | 1. 内置 --> 全局 --> 局部(函数调用) 40 | 2. 作用域 41 | 1. 全局作用域:全局名称空间 + 内置命名空间 42 | 2. 局部作用域:局部命名空间 43 | 3. `globals`查看全局作用域的内容 44 | 4. `locals`查看当前作用域的内容 45 | 46 | ```python 47 | a = 10 # 全局名称空间中的内容 48 | 49 | def fn(): # fn也在全局命名空间 50 | b = 20 # 局部名称空间 51 | print(a) 52 | def gn(): 53 | print(a) 54 | 55 | fn() 56 | gn() 57 | ``` 58 | 59 | ```python 60 | a = 10 # 全局 61 | def fn(): # 全局 62 | b = 20 # 局部 63 | def gn(): # 局部 64 | pass 65 | 66 | def en(): # 全局 67 | pass 68 | 69 | print(globals()) 70 | print(locals()) 71 | ``` 72 | 73 | 3. `global and nonlocal` 74 | 1. `global` 75 | 1. 可以把全局中的内容引入到函数内部 76 | 2. 全局中没有的变量会新建一个 77 | 2. `nonlocal` 78 | 1. 从当局往外层找对应的局部变量,但不会找全局那层,找不到会报错 79 | 2. **局部在没引用全局变量前,不能对全局变量进行修改** 80 | 81 | ```python 82 | a = 10 # 全局变量被访问的权限很大,所以不够安全 83 | def func(): 84 | # 在访问func知乎把全局中的a换成20 85 | global a 86 | a = 20 87 | 88 | func() 89 | print(a) 90 | ``` 91 | 92 | ```python 93 | def outer(): 94 | a = 10 95 | def inner(): # 在inner中改变a的值 96 | nonlocal a 97 | a = 20 98 | inner() 99 | print(a) 100 | outer() 101 | ``` 102 | 103 | ```python 104 | a = 1 105 | def fun_1(): 106 | a = 2 107 | def fun_2(): 108 | nonlocal a 109 | a = 3 110 | def fun_3(): 111 | a = 4 112 | print(a) 113 | print(a) 114 | fun_3() 115 | print(a) 116 | print(a) 117 | fun_2() 118 | print(a) 119 | print(a) 120 | fun_1() 121 | print(a) 122 | 123 | # 结果 124 | 1234331 125 | ``` 126 | 127 | ## 作业 128 | 129 | 1. 写函数,接收`n`个数字,求只写参数数字的和 130 | 131 | ```python 132 | def func(*args): 133 | sum = 0 134 | for i in args: 135 | sum += i 136 | return sum 137 | 138 | print(func(1,3,5)) 139 | ``` 140 | 141 | ```python 142 | # sum中可以直接接收一个可迭代对象,进行迭代相加 143 | def func(*args): 144 | return sum(args) 145 | 146 | print(func(1,2,3)) 147 | ``` 148 | 149 | 2. 判断返回值是什么 150 | 151 | ```python 152 | a = 10 153 | b = 20 154 | def test5(a, b): 155 | return print(a, b) 156 | 157 | c = test5(b, a) 158 | print(c) 159 | ``` 160 | 161 | 3. 写函数,传入喊中多个实参,将每个元素依次添加到`args`里(函数参数打散) 162 | 163 | ```python 164 | def func(*args): 165 | print(args) 166 | 167 | func(*[1,2,3], *'你好啊') 168 | ``` 169 | 170 | 4. 判断输出结果 171 | 172 | ```python 173 | a = 2 174 | def func(): 175 | global a 176 | a += 1 177 | print(a) 178 | func() 179 | ``` 180 | 181 | 5. 写函数,传入`n`个数,返回字典`{'max':'最大值', 'min':'最小值'}` 182 | 183 | ```python 184 | def func(*args): 185 | return {'max':max(args), 'min':min(args)} 186 | 187 | print(func(1,2,3,4)) 188 | ``` 189 | 190 | 6. 计算阶乘 191 | 192 | ```python 193 | def func(n): 194 | sum = 1 195 | while n >= 1: 196 | sum = sum * n 197 | n = n -1 198 | return sum 199 | 200 | print(func(5)) 201 | ``` 202 | 203 | 7. 扑克牌,返回`[('红心','2')·····(''黑桃','2')·······] ` 笛卡尔积 204 | 205 | ```python 206 | def func(): 207 | result = [] 208 | huase = ['红心','黑桃','草花','方片'] 209 | dianshu = [2,3,4,5,6,7,8,9,10,'J','Q','K','A'] 210 | 211 | for hua in huase: 212 | for dian in dianshu: 213 | result.append((hua, dian)) 214 | return result 215 | 216 | print(func()) 217 | ``` 218 | 219 | 8. 面试题 220 | 221 | ```python 222 | def calc(a,b,c,d=1,e=2): 223 | return (a+b)*(c-d)+e 224 | 225 | print(calc(1,2,3,4,5)) 226 | print(calc(1,2)) 227 | print(calc(e=4,c=5,a=2,b=3)) 228 | print(calc(1,2,3)) 229 | print(calc(1,2,3,e=4)) 230 | print(calc(1,2,3,d=5,4)) 231 | ``` 232 | 233 | ```python 234 | def extendList(val, list=[]): # 默认值如果是可变的的数据类型,每次使用的是同一个 235 | list.append(val) 236 | return list 237 | 238 | list1 = extendList(10) # 在默认列表里添加了10 239 | list2 = extendList(123,[]) # 使用的是默认空列表 240 | list3 = extendList('a') 241 | 242 | print(list1) 243 | print(list2) 244 | print(list3) 245 | ``` 246 | 247 | 9. 注册功能 248 | 249 | 新建`txt`文件时,要注意文件保存的编码格式 250 | 251 | ```python 252 | def regist(): 253 | print('欢迎进入注册系统') 254 | while 1: 255 | username = input('请输入用户名:').strip() 256 | password = input('请输入密码:').strip() 257 | if username == '' or password == '': 258 | print('用户名或密码不合法') 259 | continue 260 | # 校验用户名是否已经存在 261 | f = open('df.txt', mode='r+', encoding="utf-8") 262 | for line in f: 263 | if username == line.split('@@')[0]: 264 | print('对不起,该用户名已经被注册,请重新注册') 265 | break 266 | else: # 没注册过 267 | f.write('\n' + username + '@@' + password) 268 | print('注册成功了') 269 | return 270 | regist() 271 | ``` 272 | 273 | 274 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.4_拆包和交换变量值.md: -------------------------------------------------------------------------------- 1 | # 拆包和交换变量值 2 | 3 | --- 4 | 5 | ## 拆包 6 | 7 | - 拆包:元组 8 | 9 | ```python 10 | def return_num(): 11 | return 100, 200 12 | 13 | num1, num2 = return_num() 14 | print(num1) 15 | print(num2) 16 | ``` 17 | 18 | - 拆包:字典 19 | 20 | ```python 21 | dict1 = {'name':'Tom', 'age':18} 22 | a, b = dict1 23 | 24 | print(a) 25 | print(b) 26 | ``` 27 | 28 | ## 交换变量值 29 | 30 | - 方法一:借助第三变量存储数据 31 | 32 | ```python 33 | a = 10 34 | b = 20 35 | c = 0 36 | 37 | c = a 38 | a = b 39 | b = c 40 | 41 | print(a) 42 | print(b) 43 | ``` 44 | 45 | - 方法二:直接交换 46 | 47 | ```python 48 | a, b = 1, 2 49 | a, b = b, a 50 | 51 | print(a) 52 | print(b) 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.5_学员管理系统.md: -------------------------------------------------------------------------------- 1 | # 学员管理系统 2 | 3 | --- 4 | 5 | ```python 6 | # 定义功能界面函数 7 | def info_print(): 8 | print('请选择功能-------------------') 9 | print('1.添加学员') 10 | print('2.删除学员') 11 | print('3.修改学员') 12 | print('4.查询学员') 13 | print('5.显示所有学员') 14 | print('6.退出系统') 15 | print('-' * 20) 16 | 17 | 18 | # 等待存储所有学员的信息 19 | info = [] 20 | 21 | 22 | # 添加学员信息函数 23 | def add_info(): 24 | # 输入学员信息 25 | new_id = input('请输入学号:') 26 | new_name = input('请输入姓名:') 27 | new_tel = input('请输入手机号:') 28 | # 声明全局变量 29 | global info 30 | # 检查用户输入的姓名是否存在,存在则报错 31 | for i in info: 32 | if new_name == i['name']: 33 | print('该用户已存在') 34 | # 退出当前函数,不执行后面的添加信息 35 | return 36 | # 如果用户输入的姓名不存在,则添加学员信息 37 | info_dict = {} 38 | # 将用户输入的数据追加到字典 39 | info_dict['id'] = new_id 40 | info_dict['name'] = new_name 41 | info_dict['tel'] = new_tel 42 | # 将这个学员信息添加到列表 43 | info.append(info_dict) 44 | print(info) 45 | 46 | 47 | # 删除学员信息 48 | def del_info(): 49 | # 用户输入要删除的学员姓名 50 | del_name = input('请输入需要删除的学员姓名:') 51 | # 声明全局变量 52 | global info 53 | for i in info: 54 | if del_name == i['name']: 55 | info.remove(i) 56 | break 57 | else: 58 | print('该学员不存在') 59 | print(info) 60 | 61 | 62 | # 修改学员信息 63 | def modify_info(): 64 | modify_name = input('请输入需要修改的学员姓名:') 65 | global info 66 | for i in info: 67 | if modify_name == i['name']: 68 | i['tel'] = input('请输入新手机号:') 69 | break 70 | else: 71 | print('该学员不存在') 72 | print(info) 73 | 74 | 75 | # 查询学员信息 76 | def search_info(): 77 | search_name = input('请输入需要查询的学员姓名:') 78 | global info 79 | for i in info: 80 | if search_name == i['name']: 81 | print(f"该学员的学号{i['id']},姓名为{i['name']},手机号为{i['tel']}") 82 | break 83 | else: 84 | print('该学员不存在') 85 | 86 | 87 | # 显示所有学员信息 88 | def print_all(): 89 | for i in info: 90 | print(f"{i['id']}\t{i['name']}\t{i['tel']}") 91 | 92 | 93 | # 系统功能需要循环使用,知道用户输入6 94 | while True: 95 | # 1.显示功能界面 96 | info_print() 97 | 98 | # 2.用户输入功能序号 99 | user_num = int(input('请输入功能序号:')) 100 | 101 | # 3.按照用户输入的功能序号,执行不同的功能 102 | if user_num == 1: 103 | # print('添加') 104 | add_info() 105 | elif user_num == 2: 106 | del_info() 107 | elif user_num == 3: 108 | modify_info() 109 | elif user_num == 4: 110 | search_info() 111 | elif user_num == 5: 112 | print_all() 113 | elif user_num == 6: 114 | exit_flag = input('确定要退出么? yes or no') 115 | if exit_flag == 'yes': 116 | break 117 | else: 118 | print('输入功能有误') 119 | ``` 120 | 121 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.6_递归.md: -------------------------------------------------------------------------------- 1 | # 递归 2 | 3 | --- 4 | 5 | 1. 默认是死循环 6 | 2. 递归深度:自己调用自己的次数,官方文档最大递归次数是1000,在这之前就会抛出异常 7 | 3. 使用递归时,要注意写好出口,不然会死循环 8 | 9 | ```python 10 | count = 1 11 | def func(): 12 | global count 13 | print('alex很帅', count) 14 | count += 1 15 | func() 16 | func() 17 | ``` 18 | 19 | ```python 20 | # 遍历文件夹,打印出所有的文件夹和文件名 21 | import os 22 | def func(filepath, n): 23 | files = os.listdir(filepath) # 查看当前目录中的文件 24 | for file in files: 25 | # 获取到文件的路径 26 | file_p = os.path.join(filepath, file) 27 | if os.path.isdir(file_p): # 判断是否为文件夹 28 | print('\t' * n, file) 29 | func(file_p, n+1) 30 | else: 31 | print('\t'*n, file) 32 | func('D:/repository', 0) 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.7_lambda匿名函数.md: -------------------------------------------------------------------------------- 1 | # `lambda`匿名函数 2 | 3 | --- 4 | 5 | 语法:`lambda 参数:返回值` 6 | 7 | 1. 可以有多个参数,参数间用逗号隔开 8 | 2. 只能写一行,直接返回数据 9 | 3. 返回值和正常函数一样,可以是任意数据 10 | 4. 不要写复杂的逻辑 11 | 5. 当用到简单的逻辑可以直接用`lambda`写,方便快捷不用再重新写函数 12 | 13 | ```python 14 | a = lambda n : n * n 15 | ret = a(9) 16 | print(ret) 17 | ``` 18 | 19 | ```python 20 | # 根据传递参数的函数名打印 21 | def func(): 22 | print('您好') 23 | def func2(): 24 | print('不好') 25 | def gn(fn): # fn是一个参数,根据传进来的参数不同打印的名字不同 26 | print(fn.__name__) 27 | fn() 28 | gn(func2) 29 | ``` 30 | 31 | ```python 32 | # suiyi = lambda x, y : x, y y要申明,会报错 33 | suiyi = lambda x, y : (x, y) # 括起来才是多参数返回 34 | ``` 35 | 36 | ```python 37 | # 传递两个参数,返回最大值 38 | a = lambda x, y : max(x, y) 39 | print(a(1,2)) 40 | # 多参数 41 | b = lambda *args : max(*args) 42 | print(b(1,2,3,4,5,6)) 43 | ``` 44 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.8_sorted()排序函数.md: -------------------------------------------------------------------------------- 1 | # `sorted()`排序函数 2 | 3 | --- 4 | 5 | 语法:`sorted(iterable, key=None, reberse=False)` 6 | 7 | 返回的是列表不是地址 8 | 9 | ```python 10 | lst = [16, 18, 32, 54, 12, 9] 11 | lst.sort() # list的方法 12 | s = sorted(lst) # 内置函数都会有返回值 13 | print(s) 14 | 15 | lst = ['聊斋', '西游记', '三国演义', '葫芦娃', '水浒传', '年轮', '亮剑'] 16 | def func(s): 17 | return len(s) 18 | ll = sorted(lst, key=func) 19 | # 排序反感,sorted函数内部会把可迭代对象中的每一个元素拿出来交给后面的key后面的方法计算一个数字,作为当前这个元素的权重进行排序 20 | print(ll) 21 | ``` 22 | 23 | ```python 24 | lst = [ 25 | {'name':'汪峰', 'age':48}, 26 | {'name':'章子怡', 'age':38}, 27 | {'name':'alex', 'age':39}, 28 | {'name':'wusir', 'age':32}, 29 | {'name':'赵一宁', 'age':28} 30 | ] 31 | def func(el): 32 | return ed['age'] 33 | ll = sorted(lst, key=func) 34 | lc = sorted(lst, key=lambda el: el['age'], reverse=True) 35 | print(ll) 36 | print(lc) 37 | ``` 38 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.2.1.9_filter过滤函数.md: -------------------------------------------------------------------------------- 1 | # `filter`过滤函数 2 | 3 | --- 4 | 5 | ```python 6 | lst = ['张无忌', '张铁林', '张怡宁', '史可心', '马大帅'] 7 | def func(el): 8 | if el[0] == '张': 9 | return False 10 | else: 11 | return True 12 | # 将lst中的每一项传给func,所有返回True的都会保留 13 | 14 | f = filter(func, lst) 15 | g = filter(lambda el: el[0] != '张', lst) 16 | 17 | print('__iter__' in dir(f)) # 判断是否可以迭代 18 | for e in f: 19 | print(e) 20 | for i in g: 21 | print(i) 22 | ``` 23 | 24 | ```python 25 | lst = [ 26 | {'name':'汪峰', 'score':48}, 27 | {'name':'章子怡', 'score':39}, 28 | {'name':'alex', 'score':97}, 29 | {'name':'wusir', 'score':90}, 30 | {'name':'赵一宁', 'score':76} 31 | ] 32 | f = filter(lambda el: el['score'] > 60, lst) 33 | print(list(f)) 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.3.1.10_闭包和迭代器.md: -------------------------------------------------------------------------------- 1 | # 闭包和迭代器 2 | 3 | --- 4 | 5 | ## 闭包 6 | 7 | 1. 在内层函数中访问外层函数的局部变量 8 | 2. 闭包的作用 9 | 10 | 1. 保护变量不受侵害 11 | 2. 可以让一个变量常驻内存 12 | 3. 写法 13 | ```python 14 | def outer(): 15 | a = 10 16 | def inner(): 17 | print(a) 18 | return inner 19 | 20 | ret = outer() # 先加载耗时程序 21 | ret() # 再执行就会很快 22 | ``` 23 | 24 | ```python 25 | def outer(): 26 | a = 10 27 | def inner(): 28 | print(a) 29 | inner() 30 | outer() 31 | ``` 32 | 33 | ```python 34 | def outer(): 35 | a = 10 # 对外界不开放 36 | def inner(): 37 | nonlocal a 38 | a = 20 39 | print(a) 40 | inner() 41 | outer() 42 | ``` 43 | 44 | ```python 45 | # 超简易爬虫 46 | from urllib.request import urlopen 47 | 48 | def outer(): 49 | s = urlopen('http://www.521609.com/').read() 50 | def getCountent(): 51 | return s # 第一次拿比较慢,之后就很快 52 | return getCountent 53 | 54 | pa = outer() 55 | ret = pa() 56 | print(ret) 57 | print(ret) # 由于内容常驻在内存里,后面的内容不会因为网络原因导致速度很慢 58 | ``` 59 | 60 | ```python 61 | # 查看是否为闭包 62 | def func(): 63 | a = 10 64 | def inner(): 65 | print(a) 66 | print(inner.__closure__) 67 | 68 | func() 69 | ``` 70 | 71 | ## 迭代器 72 | 73 | 1. 所有带`__iter__`可以使用`for`循环,是可迭代对象 74 | 2. 可迭代对象可以使用`__iter__()`来获取迭代器 75 | 3. **迭代器**里面有`__next__()` 76 | 4. 可以用`dir`来判断 数据是否可迭代,以及数据是否是迭代器 77 | 5. 惰性机制 78 | 6. 主要是遍历可迭代对象 79 | 7. 只能向前 80 | 8. 省内存 81 | 82 | ```python 83 | print(dir(str)) # dir查看xx类型的数据可以执行哪些方法 84 | 85 | s = '史可心' 86 | it = s.__iter__() # 获取迭代器 87 | print(dir(it)) 88 | 89 | # 只能向前 90 | # 几乎不占用内存,节省内存 91 | # 很少直接用,用for循环 92 | print(it.__next__()) 93 | print(it.__next__()) 94 | ``` 95 | 96 | ```python 97 | # 用迭代器模拟for循环 98 | lst = ['赵一宁', '史可心', '朱奎峰', '姚明'] 99 | it = lst.__iter__() # 获取迭代器 100 | while 1: # 没有内容后报错 101 | try: # 避免程序报错 102 | el = it.__next__() 103 | print(el) 104 | except StopIteration: 105 | break 106 | ``` 107 | 108 | ```python 109 | lst = ['赵一宁', '史可心', '朱奎峰', '姚明'] 110 | it = lst.__iter__() 111 | 112 | # list(参数)把参数循环迭代 113 | s = list(it) # 在list中一定存在for循环,会有__next__() 114 | print(s) 115 | ``` 116 | 117 | ## 作业 118 | 119 | 1. 星号直角三角形 120 | 121 | ```python 122 | for i in range(1, 6): 123 | print('*' * i) 124 | 125 | for i in range(1, 6): 126 | for j in range(i): 127 | print('*', end=' ') 128 | print() 129 | ``` 130 | 131 | 2. 等腰三角形 132 | 133 | ```python 134 | # 空格和星号分开打印 135 | n = 6 136 | for i in range(1, n): 137 | for k in range(2 * n - 2 * i): 138 | print('', end=' ') 139 | for j in range(2 * i - 1): 140 | print('*', end=' ') 141 | print() 142 | ``` 143 | 144 | 3. 枚举 145 | 146 | ```python 147 | lst = ['哈哈', '吼吼', '嘿嘿', '嘻嘻'] 148 | for i in enumerate(lst): 149 | print(i) 150 | for i in enumerate(lst, 1): 151 | print(i) 152 | for i, v in enumerate(lst, 1): 153 | print(i, v) 154 | ``` 155 | 156 | 4. 大作业:购物车 -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.3.1.11_生成器.md: -------------------------------------------------------------------------------- 1 | # 生成器 2 | 3 | --- 4 | 5 | ## 生成器 6 | 7 | 1. 生成器的本质就是迭代器 8 | 2. 生成器的特点和迭代器一样,取值方式和迭代器一样 9 | 3. 生成器一般由生成器函数或者生成器表达式来创建 10 | 4. 其实就是手写的迭代器 11 | 12 | ## 生成器函数 13 | 14 | 1. `yield`相当于`return`,可以返回数据,但是`yield`不会彻底中断函数,分段执行函数 15 | 2. 函数中如果有`yield`,这个函数就是生成器函数,生成器函数(),获取的是生成器函数,并没有执行 16 | 3. `gen._next_()`执行函数,执行到下一个`yield` 17 | 4. `gen._next_()`继续执行函数到下一个`yield` 18 | 19 | ```python 20 | def func(): 21 | print('娃哈哈') 22 | yield 1 23 | print('呵呵呵') 24 | gen = func() # 不会执行函数,拿到的是生成器 25 | print(func()) 26 | ret = gen.__next__() # 会执行到下一个yield 27 | print(ret) 28 | gen.__next__() # StopIteration 29 | ``` 30 | 31 | ```python 32 | def order(): 33 | for i in range(10000): 34 | yield '衣服' + str(i) 35 | 36 | ll = order() # 获取生成器 37 | mingwei = ll.__next__() 38 | print(mingwei) 39 | zhaoyining = ll.__next__() 40 | print(zhaoyining) 41 | ``` 42 | 43 | 5. `send()`函数 44 | 45 | 1. 和`_next_()`一样,可以执行到下一个`yield`,可以可上一个`yield`位置传值 46 | 2. `send()`必须给参数,不能用在结尾 47 | 3. 开头必须是`__next__()` 48 | 49 | ```python 50 | def func(): 51 | print('我是第一段') 52 | a = yield 123 53 | print(a) 54 | print('我是第二段') 55 | b = yield 456 56 | print(b) 57 | print('我是第三段') 58 | c = yield 789 59 | print(c) 60 | print('我是最后一段') 61 | yield 79 62 | 63 | g = func() # 获得生成器 64 | print(g) 65 | print(g.__next__()) 66 | print(g.send('煎饼果子')) 67 | print(g.send('韭菜盒子')) 68 | print(g.send('锅包肉')) 69 | ``` 70 | 71 | ```python 72 | def eat(): 73 | print('我吃什么啊') 74 | a = yield '馒头' 75 | print('a=', a) 76 | b = yield '鸡蛋灌饼' 77 | print('b=', b) 78 | c = yield '韭菜盒子' 79 | print('c=', c) 80 | yield 'game over' 81 | 82 | gen = eat() 83 | ret1 = gen.__next__() 84 | print(ret1) 85 | ret2 = gen.send('胡辣汤') 86 | print(ret2) 87 | ret3 = gen.send('狗粮') 88 | print(ret3) 89 | ret4 = gen.send('猫粮') 90 | print(ret4) 91 | ``` 92 | 93 | ```python 94 | def func(): 95 | yield 1 96 | yield 13 97 | yield 26 98 | yield 23 99 | for i in func(): # for的内容部一定有__next__() 100 | print(i) 101 | print(list(func())) 102 | ``` 103 | 104 | ## 列表/字典/集合推导式 105 | 106 | 1. 用一句话来生成一个列表 `[结果 for循环]` 107 | 2. 不要用推导式处理过分复杂的东西 108 | 3. 没有元组推导式---元组不能增删改 109 | 110 | ```python 111 | lst = ['python' + str(i) for i in range(1, 16)] 112 | print(lst) 113 | 114 | lst = [i for i in range(100) if i%2 == 1] 115 | print(lst) 116 | 117 | lst = [i ** 2 for i in range(1, 100) if i % 3 == 0] 118 | print(lst) 119 | 120 | names = [['Tom','Billy','Jefferson','Andrew','Wesley','Joe'],['Alice','Jill','Ana','Wendy','Jennifer','Sherry','Eva']] 121 | lst = [name for line in manes for name in line if name.count('e') == 2] # 检测是否包括大写 122 | 123 | # 字典推导式 124 | lst = [11,22,33,44] 125 | dic = {i:lst[i] for i in range(len(lst)) if i < 2} 126 | print(dic) 127 | 128 | # 字典键值装换 129 | dic = {'jj':'林俊杰', 'jay':'周杰伦', 'zs':'赵四', 'ln':'刘能'} 130 | dic1 = {v : k for k,v in dic.items()} 131 | print(dic1) 132 | 133 | # 集合推导式 134 | s = {i for i in range(1000)} 135 | print(s) 136 | 137 | lst = [1,2,1,3,2,4,5] 138 | s = set(lst) 139 | print(s) 140 | s1 = {i for i in lst} 141 | print(s1) 142 | ``` 143 | 144 | ## 生成器表达式 145 | 146 | **惰性机制,只能向前,节省内存** 147 | 148 | ```python 149 | tu = (i for i in range(10)) 150 | print(tu) # 是个生成器 151 | print(tu.__next__()) 152 | ``` 153 | 154 | ```python 155 | def func(): # 生成器函数 156 | print(111) 157 | yield 222 158 | g = func() # 获取生成器 159 | g1 = (i for i in g) # 生成器 160 | g2 = (i for i in g1) # 生成器 161 | g3 = func() # 增加取值来源 162 | g4 = (i for i in g3) 163 | print(list(g)) # 从源头把数据拿走了 164 | print(list(g1)) # 执行的时候按步骤向源头拿值,但是源头已经没有数据了 165 | print(list(g2)) 166 | ``` 167 | 168 | ```python 169 | def func(): # 生成器函数 170 | print(111) 171 | yield 222 172 | g = func() # 获取生成器 173 | g1 = (i for i in g) # 生成器 174 | g2 = (i for i in g1) # 生成器 175 | g3 = func() # 增加取值来源 176 | g4 = (i for i in g3) 177 | print(list(g2)) 178 | print(list(g)) 179 | print(list(g1)) 180 | print(list(g4)) 181 | ``` 182 | 183 | ```python 184 | def add(a, b): 185 | return a + b 186 | def test(): 187 | for i in range(4): 188 | yield i 189 | g = test() 190 | for n in [2, 10]: 191 | g = (add(n, i) for i in g) 192 | # 上面的for循环嘲讽 193 | # n = 2 g = (add(n, i) for i in g) 第一步 生成器,没有拿值 这一步没有运算过 194 | # n = 10 g = (add(n, i) for i in (add(n, i) for i in g)) 第二步 生成器,没有拿值 195 | # list(g) 第二步拿值,和第一步没关系,不用考虑 196 | # 只循环公式,算值只有一次 197 | print(list(g)) 198 | ``` 199 | 200 | ```python 201 | def add(a, b): 202 | return a + b 203 | def test(): 204 | for i in range(4): 205 | yield i 206 | g = test() 207 | for n in [2, 10, 5]: 208 | g = (add(n, i) for i in g) 209 | # (add(n, i) for i in (add(n, i) for i in (add(n, i) for i in g))) 210 | print(list(g)) 211 | ``` 212 | 213 | ## 作业 214 | 215 | 1. 筛选长度大于三 216 | 217 | ```python 218 | lst = ['kobe','anthonmy','史可','吴彦','山本五十六','松下索尼阿玛尼'] 219 | ll = [name.upper() for name in lst if len(name) > 3] 220 | print(ll) 221 | ``` 222 | 223 | 2. `(x,y)`,`x`是`0 - 5`偶数,`y`是`0 - 5`奇数 224 | 225 | ```python 226 | tu = [(x,y) for x in range(6) for y in range(6) if x % 2 == 0 and y % 2 ==1] 227 | print(tu) 228 | ``` 229 | 230 | 3. `[[1,2,3],[4,5,6],[7,8,9]] <--> [3,6,9]` 231 | 232 | ```python 233 | M = [[1,2,3],[4,5,6],[7,8,9]] 234 | lst = [i[2] for i in M] 235 | print(lst) 236 | 237 | lst = [3, 6, 9] 238 | lst1 = [[i-2, i-1, i] for i in lst] 239 | print(lst1) 240 | ``` 241 | 242 | 4. 元素加索引 243 | 244 | ```python 245 | lst =['alex','wusir','老男孩','太白'] 246 | print([el+str(index) for index,el in enumerate(lst)]) 247 | ``` 248 | 249 | 250 | 251 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/2.3.1.12_装饰器.md: -------------------------------------------------------------------------------- 1 | # 装饰器 2 | 3 | --- 4 | 5 | 装饰器本质上是一个`Python`函数,他可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。他经常用于有切面需求的场景,如插入日志、性能测试、实务处理、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,就可以抽离出大量与函数本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。 6 | 7 | ## 简单装饰器 8 | 9 | ```python 10 | import time 11 | 12 | a = 5 13 | b = 1 14 | 15 | def decorator(func): 16 | def inner(a,b): 17 | print(f'输入参数 a={a},b={b}') 18 | f1 = func(a,b) 19 | print(f'当前时间是 = {time.ctime()}') 20 | return f1 21 | return inner 22 | 23 | @decorator 24 | def add(a,b): 25 | return a + b 26 | 27 | @decorator 28 | def sub(a,b): 29 | return a - b 30 | 31 | print(f'{a} + {b} = {add(a,b)}') 32 | print(f'{a} - {b} = {sub(a,b)}') 33 | ``` 34 | 35 | ## 使用装饰器传递参数 36 | 37 | 在上面的装饰器调用中,如`@decorator`,该装饰器默认他后面的函数是唯一的参数。装饰器的语法允许调用`@decorator`时,向他传入参数,这样就为装饰器的编写和使用提供了更大的灵活性。 38 | 39 | ```python 40 | import time 41 | 42 | a = 5 43 | b = 1 44 | 45 | def pre_str(pre=''): 46 | def decorator(func): 47 | def inner(a,b): 48 | print(f'输入参数 a={a},b={b}') 49 | f1 = func(a,b) 50 | print(f'当前时间是 = {time.ctime()}') 51 | return f1 52 | return inner 53 | return decorator 54 | 55 | @pre_str('add') 56 | def add(a,b): 57 | return a + b 58 | 59 | @pre_str('sub') 60 | def sub(a,b): 61 | return a - b 62 | 63 | print(f'{a} + {b} = {add(a,b)}') 64 | print(f'{a} - {b} = {sub(a,b)}') 65 | ``` 66 | 67 | ## 基于类的装饰器 68 | 69 | 有待理解。。。。。。 -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/内置函数.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/2.2_Python进阶/2.2.1_函数/内置函数.xmind -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.2_面向对象/2.2.2.2_面向对象属性.md: -------------------------------------------------------------------------------- 1 | # 面向对象属性 2 | 3 | --- 4 | 5 | 属性即是特征,比如:洗衣机的宽度,高度,重量。。。对象属性既可以在类外面添加和获得,也能在类里面添加和获得。 6 | 7 | ## 公共属性 8 | 9 | 在类的内部中可以定义属性和方法,在方法内封装负载的业务逻辑,通过类的对象访问方法。但是类的属性既可以在类的内部访问和修改,也可以通过类的对象进行访问和修改,这样会破坏数据的封装。 10 | 11 | ```python 12 | class Student(object): 13 | 14 | def __init__(self, name, age): 15 | self.name = name 16 | self.age = age 17 | 18 | def info(self): 19 | print(f'{self.name}, {self.age}') 20 | 21 | stu = Student('Tom', 21) 22 | stu.name = 'Jim' 23 | stu.age = 25 24 | print(f'{stu.name}, {stu.age}') 25 | ``` 26 | 27 | 从本例可以看出,在`Student`类的内部定义了`name`和`age`两个属性,既可以在类的内部进行访问,也可以通过`Student`类的对象进行访问和修改。如果要让类的属性不能被外部访问,可以在属性的名称前加上两个下划线。 28 | 29 | ### 类外面添加属性 30 | 31 | ```python 32 | class Washer(): 33 | def wash(self): 34 | print('洗衣服') 35 | 36 | haier1 = Washer() 37 | 38 | # 添加属性 39 | haier1.width = 400 40 | haier1.height = 500 41 | ``` 42 | 43 | ### 类外面获取属性 44 | 45 | ```python 46 | class Washer(): 47 | def wash(self): 48 | print('洗衣服') 49 | 50 | haier1 = Washer() 51 | 52 | # 添加属性 53 | haier1.width = 400 54 | haier1.height = 500 55 | 56 | # 获取属性 57 | print(f'洗衣机的宽度是{haier1.width}') 58 | print(f'洗衣机的高度是{haier1.height}') 59 | ``` 60 | 61 | ### 类里面获取对象属性 62 | 63 | ```python 64 | class Washer(): 65 | def wash(self): 66 | print('洗衣服') 67 | 68 | # 获取对象属性 69 | def pritn_info(self): 70 | print(f'洗衣机的宽度是{haier1.width}') 71 | print(f'洗衣机的高度是{haier1.height}') 72 | 73 | haier1 = Washer() 74 | 75 | # 添加属性 76 | haier1.width = 400 77 | haier1.height = 500 78 | 79 | # 对象调用方法 80 | heier1.print_info() 81 | ``` 82 | 83 | ## 私有属性和方法 84 | 85 | `Python`中定义类的属性时,如果属性的名称以两个下划线开头则表示是私有属性。私有属性在类的外部不能直接访问,需要通过调用对象的共有方法来访问。子类可以继承父类的公有成员,但是不能继承其私有成员。 86 | 87 | ```python 88 | class Student(object): 89 | 90 | def __init__(self, name, age): 91 | # 定义私有属性,私有属性在类外部无法直接访问 92 | self.__name = name 93 | self.__age = age 94 | 95 | def info(self): 96 | print(f'{self.name}, {self.age}') 97 | 98 | stu = Student('Tom', 21) 99 | ``` 100 | 101 | 修改后只能在类的内部访问私有属性,如果使用对象直接访问私有属性会报错。 102 | 103 | `print(stu.__name)` 104 | 105 | 在类中还可以定义私有方法,私有方法的名称以两个下划线开始,在私有方法中以访问类的所有属性,只能在类的内部调用私有方法,无法通过对象调用私有方法,也无法继承。 106 | 107 | ```python 108 | class Student(object): 109 | 110 | def __init__(self, name, age): 111 | # 定义私有属性,私有属性在类外部无法直接访问 112 | self.__name = name 113 | self.__age = age 114 | 115 | def __printFun(self): 116 | print(f'{self.name}, {self.age}') 117 | 118 | def info(self): 119 | print(f'{self.name}, {self.age}') 120 | 121 | stu = Student('Tom', 21) 122 | stu.info() 123 | ``` 124 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.2_面向对象/2.2.2.3_面向对象魔法方法.md: -------------------------------------------------------------------------------- 1 | # 面向对象魔法方法 2 | 3 | --- 4 | 5 | ## `__init__`方法 6 | 7 | `Python`中类的构造函数是`__init__()`,一般用来为类的属性设置初值或进行其他必要的初始化工作,在创建对象时被自动调用和执行。如果用户没有涉及构造函数,`Python`将提供一个默认的构造函数进行必要的初始化工作。`__init__()`方法的第一个参数是`self`,表示创建的实例本身。 8 | 9 | 在初始化类时,可以通过`self`属性的方式对类的属性进行赋值,在`__init__()`方法中定义的属性是实例属性,用于记录该对象的特别信息。在类的方法中通过`self`属性的方式获得在`__init__()`方法中初始化的属性值。 10 | 11 | ```python 12 | class People(object): 13 | # 定义构造方法 14 | def __init__(self, name, gender): 15 | # 实例属性 16 | self.name = name 17 | self.gender = gender 18 | def speak(self): 19 | """ people can speak """ 20 | print(f'{self.name}的属性是{self.gender}') 21 | ``` 22 | 23 | 面向对象编程的一个重要特点是数据封装,在`Poeple`类的`__init__()`方法中初始化的实例属性`name`和`gender`,可以在类的方法中通过类的对象访问类的实例属性。 24 | 25 | ```python 26 | # 初始化对象 27 | people = People('Tom', 'Male') 28 | people.speak() 29 | ``` 30 | 31 | 也可以通过类的对象访问实例属性,类的实例属性可以被累的对象访问和修改。 32 | 33 | ```python 34 | people.name = 'Jim' 35 | people.gender = 'female' 36 | print(f'{people.name}的属性是{people.gender}') 37 | ``` 38 | 39 | ## `__str__`方法 40 | 41 | 当使用`print`输出对象的时候,默认打印对象的内存地址。如果类定义了`__str__`方法,那么就会打印从在这个方法中`return`的数据。 42 | 43 | ```python 44 | class Washer(): 45 | def __init__(self): 46 | self.width = 300 47 | 48 | def __str__(self): 49 | return '解释说明:类的说明或对象状态说明' 50 | 51 | haier = Washer() 52 | print(haier) 53 | ``` 54 | 55 | ## `__del__`方法 56 | 57 | 当删除对象时,`python`解释器也会默认调用`__del__()`方法。即便不设置也可以自动调用。 58 | 59 | ```python 60 | class Washer(): 61 | def __init__(self): 62 | self.width = 300 63 | 64 | def __del__(self): 65 | print('对象已经删除') 66 | 67 | haier = Washer() 68 | ``` 69 | 70 | ## `__dict__`方法 71 | 72 | 可以访问类的所有属性,以字典的形式返回。 73 | 74 | ```python 75 | class People(object): 76 | def __init__(self, name, age): 77 | self.name = name 78 | self.age = age 79 | 80 | people = People('Tom', 22) 81 | print(people.__dict__) 82 | print('name=', people.__dict__['name']) 83 | ``` 84 | 85 | ## `__slots__`方法 86 | 87 | 可以把实例属性锁定到`__slots__`规定的范围内。 88 | 89 | ```python 90 | class Student(object): 91 | pass 92 | 93 | s = Student() 94 | s.name = 'lisi' 95 | print(s.name) 96 | ``` 97 | 98 | 限制实例属性 99 | 100 | ```python 101 | class Student(object): 102 | __slots__ = ('name', 'age') 103 | 104 | def __init__(self, name, age): 105 | self.name = name 106 | self.age = age 107 | 108 | stu = Student('Tom', 25) 109 | print(f'name={stu.name}, age={stu.age}') 110 | stu.score = 90 # 会报错 111 | ``` 112 | 113 | 使用`__slots__`要注意,`__slots__`定义的属性仅对当前类实例起作用,对继承它的子类是不起作用的。 114 | 115 | ## `__call__()`方法 116 | 117 | 在`Python`中,函数也是一种对象。实际上,任何一个有`__call__()`特殊方法的对象都被当做是函数。 118 | 119 | ```python 120 | class Add(object): 121 | def __call__(self, a) 122 | return a + 5 123 | 124 | add = Add() 125 | print(add(2)) 126 | ``` 127 | 128 | 所有的函数都是可调用对象,因此`add`被称为可调用对象。 -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.2_面向对象/2.2.2.4_实例应用.md: -------------------------------------------------------------------------------- 1 | # 综合应用 2 | 3 | --- 4 | 5 | ## 烤地瓜 6 | 7 | ```python 8 | class SweetPotato(): 9 | 10 | def __init__(self): 11 | # 被考的时间 12 | self.cook_time = 0 13 | # 地瓜的状态 14 | self.cook_state = '生的' 15 | # 调料列表 16 | self.condiments = [] 17 | 18 | def __str__(self): 19 | return f'这个地瓜被烤过的时间{self.cook_time},状态是{self.cook_state},添加的调料是{self.condiments}' 20 | 21 | def cook(self, time): 22 | # 烤地瓜方法 23 | # 1.先计算地瓜整体烤过的时间 24 | self.cook_time += time 25 | # 2.用整体烤过的时间判断地瓜状态 26 | if 0 <= self.cook_time <3: 27 | self.cook_state = '生的' 28 | elif 3 <= self.cook_time < 5: 29 | self.cook_state = '半生不熟' 30 | elif 5 <= self.cook_time < 8: 31 | self.cook_state = '熟了' 32 | elif self.cook_time >= 8: 33 | self.cook_state = '烤糊了' 34 | 35 | def add_condiments(self, condiments): 36 | # 用户医院的调料追加到列表 37 | self.condiments.append(condiments) 38 | 39 | 40 | # 2.创建对象并调用对应的实例方法 41 | digua1 = SweetPotato() 42 | print(digua1) 43 | 44 | digua1.cook(2) 45 | digua1.add_condiments('辣椒面') 46 | print(digua1) 47 | 48 | digua1.cook(2) 49 | digua1.add_condiments('蜂蜜') 50 | print(digua1) 51 | ``` 52 | 53 | ## 搬家具 54 | 55 | ```python 56 | class Furniture(): 57 | 58 | def __init__(self, name, area): 59 | self.name = name 60 | self.area = area 61 | 62 | 63 | class Home(): 64 | 65 | def __init__(self, address, area): 66 | # 地理位置 67 | self.address = address 68 | # 房屋面积 69 | self.area = area 70 | # 剩余面积 71 | self.free_area = area 72 | # 家具列表 73 | self.furniture = [] 74 | 75 | def __str__(self): 76 | return f'房子地理位置在{self.address},房屋面积{self.area},剩余面积{self.free_area},家具有{self.furniture}' 77 | 78 | def add_furniture(self, item): 79 | # 容纳家具 80 | # 如果家具面积 <= 房子面积:搬入家具 81 | if item.area <= self.free_area: 82 | self.furniture.append(item.name) 83 | self.free_area -= item.area 84 | else: 85 | print('房屋面积不够了') 86 | 87 | 88 | bed = Furniture('双人床', 6) 89 | sofa = Furniture('沙发', 1000) 90 | 91 | home = Home('上海', 1000) 92 | print(home) 93 | 94 | home.add_furniture(bed) 95 | print(home) 96 | 97 | home.add_furniture(sofa) 98 | print(home) 99 | ``` 100 | 101 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.2_面向对象/2.2.2.6_面向对象多态.md: -------------------------------------------------------------------------------- 1 | # 多态 2 | 3 | --- 4 | 5 | 多种形态或多种状态,即参数可以是多种类型,可以是列表,字典,字符串。。。。由于`python`原生支持多态,所以没有特殊性。 6 | 7 | 鸭子模型:只要可以嘎嘎叫就是鸭子 8 | 9 | ```python 10 | def func(arg): 11 | arg.send() 12 | ``` 13 | 14 | ```python 15 | class Foo1(): 16 | def f1(self): 17 | pass 18 | class Foo2(): 19 | def f1(self): 20 | pass 21 | class Foo3(): 22 | def f1(self): 23 | pass 24 | def func(arg): 25 | arg.f1() 26 | 27 | obj = Foo1() 28 | func(obj) 29 | ``` 30 | 31 | ## 作业 32 | 33 | 1. 定义一个类,其中有计算圆周长和面积的方法 34 | 35 | ```python 36 | class Circle: 37 | def __init__(self, r): 38 | self.r = r 39 | self.pi = 3.14 40 | 41 | def long(self): 42 | return 2 * self.pi * self.r 43 | 44 | def mianji(self): 45 | return self.pi * self.r ** 2 46 | 47 | 48 | obj = Circle(5) 49 | print(obj.long()) 50 | print(obj.mianji()) 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.10_面向对象版学员管理系统.md: -------------------------------------------------------------------------------- 1 | # 面向对象版学员管理系统 2 | 3 | --- 4 | 5 | 在写项目时,需要在`pycharm`中新建包,这样方便引用自己写的模块。 6 | 7 | `student`模块 8 | 9 | ```python 10 | class Student(object): 11 | 12 | def __init__(self, name, gender, tel): 13 | self.name = name 14 | self.gender = gender 15 | self.tel = tel 16 | 17 | def __str__(self): 18 | return f'{self.name}\t{self.gender}\t{self.tel}' 19 | ``` 20 | 21 | `managerSystem`模块 22 | 23 | ```python 24 | from student import * 25 | 26 | 27 | class StudentManager(object): 28 | 29 | def __init__(self): 30 | self.student_list = [] 31 | 32 | # 一、程序入口函数 33 | def run(self): 34 | # 1.加载文件里面的学员数据 35 | self.load_student() 36 | while True: 37 | # 2.显示功能菜的 38 | self.show_menu() 39 | # 3.用户输入目标功能序号 40 | menu_num = int(input('请输入您需要的功能序号:')) 41 | # 4.根据用户输入的序号执行功能 42 | if menu_num == 1: 43 | # 添加学员 44 | self.add_student() 45 | elif menu_num == 2: 46 | # 删除学员 47 | self.del_student() 48 | elif menu_num == 3: 49 | # 修改学员信息 50 | self.modify_student() 51 | elif menu_num == 4: 52 | # 查询学员信息 53 | self.search_student() 54 | elif menu_num == 5: 55 | # 显示所有学员信息 56 | self.show_student() 57 | elif menu_num == 6: 58 | # 保存学员信息 59 | self.save_student() 60 | elif menu_num == 7: 61 | # 退出系统 62 | break 63 | 64 | # 二、系统功能函数 65 | # 2.1 显示功能菜单 66 | @staticmethod 67 | def show_menu(): 68 | print('请选择如下功能:') 69 | print('1:添加学员信息') 70 | print('2:删除学员信息') 71 | print('3:修改学员信息') 72 | print('4:查询学员信息') 73 | print('5:显示所有学员信息') 74 | print('6:保存学员信息') 75 | print('7:退出系统') 76 | 77 | # 2.2 添加学员信息 78 | def add_student(self): 79 | name = input('请输入您的姓名:') 80 | gender = input('请输入您的性别:') 81 | tel = input('请输入您的手机号:') 82 | 83 | student = Student(name, gender, tel) 84 | self.student_list.append(student) 85 | 86 | # 2.3 删除学员信息 87 | def del_student(self): 88 | del_name = input('请输入删除的学员姓名:') 89 | for i in self.student_list: 90 | if del_name == i.name: 91 | self.student_list.remove(i) 92 | break 93 | else: 94 | print('查无此人') 95 | print(self.student_list) 96 | 97 | # 2.4 修改学员信息 98 | def modify_student(self): 99 | modify_name = input('请输入修改学员姓名:') 100 | for i in self.student_list: 101 | if modify_name == i.name: 102 | i.name = input('姓名:') 103 | i.gender = input('性别:') 104 | i.tel = input('手机号:') 105 | print(f'修改学员信息成功,姓名{i.name},性别{i.gender},手机号{i.tel}') 106 | break 107 | else: 108 | print('查无此人') 109 | 110 | # 2.5 查询学员信息 111 | def search_student(self): 112 | search_name = input('请输入您要搜索的学员姓名:') 113 | for i in self.student_list: 114 | if search_name == i.name: 115 | print(f'{i.name}\t{i.gender}\t{i.tel}') 116 | break 117 | else: 118 | print('查无此人') 119 | 120 | # 2.6 显示所有学员信息 121 | def show_student(self): 122 | print('姓名\t性别\t手机号') 123 | for i in self.student_list: 124 | print(f'{i.name}\t{i.gender}\t{i.tel}') 125 | 126 | # 2.7 保存学员信息 127 | def save_student(self): 128 | with open('student.data', 'w', encoding='utf-8') as f: 129 | new_list = [i.__dict__ for i in self.student_list] 130 | f.write(str(new_list)) 131 | 132 | # 2.8 加载学员信息 133 | def load_student(self): 134 | try: 135 | f = open('student.data', 'r', encoding='utf-8') 136 | except: 137 | f = open('student.data', 'w', encoding='utf-8') 138 | else: 139 | data = f.read() 140 | new_list = eval(data) 141 | self.student_list = [Student(i['name'], i['gender'], i['tel']) for i in new_list] 142 | f.close() 143 | ``` 144 | 145 | `main`模块 146 | 147 | ```python 148 | from managerSystem import * 149 | 150 | 151 | if __name__ == '__main__': 152 | student_manger = StudentManager() 153 | student_manger.run() 154 | ``` 155 | 156 | 不太明白为什么要写`student`类。。。 -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.1_模块和包.md: -------------------------------------------------------------------------------- 1 | # 模块和包 2 | 3 | --- 4 | 5 | ## 模块 6 | 7 | 序列是数据的封装,函数是语句的封装,类是方法和属性的封装。从本质上说,函数和类都是为了跟好的组织已有的程序,以便被其他程序调用。 8 | 9 | 模块也是为了同样的目的。模块是程序的封装,在`Python`中,一个后缀为`.py`的文件就是一个模块。通过模块,可调用其他`.py`文件中的程序。 10 | 11 | ### 导入模块 12 | 13 | ```python 14 | import math 15 | data = math.pow(3, 2) 16 | ``` 17 | 18 | 一个模块只会被导入一次,而且无论执行了多少次`import`。这样可以防止导入模块被重复执行。其他几种导入模块方法。 19 | 20 | ```python 21 | import moduleName as shortName 22 | form modname import name 23 | form modname import * 24 | ``` 25 | 26 | ### 模块的`__name__`属性 27 | 28 | 在`C`语言中`main`函数是程序执行的起点,`Python`作为一种脚本语言也有类似的运行机制,`Python`使用缩进对齐来组织代码的执行,用`Python`写的各个模块都可以包含一个`C`语言中的`main`函数,只不过`Python`中的这种`__main__`与`C`预言者的有一些区别。 29 | 30 | 每个模块都是一个独立的后缀为`.py`文件,模块就是诚信,可以当做诚信来执行。当做程序执行时需要一个入口点类似于`C`语言的`main`函数。 31 | 32 | 只在当前文件中调用该函数,其他导入的文件内不符合该条件,则不执行测试函数。 33 | 34 | ```python 35 | def sayHello(): 36 | print('hello python') 37 | 38 | if __name__ == "__main__": 39 | print('This is main of module "hello.py"') 40 | sayHello() 41 | ``` 42 | 43 | ### 以程序方式运行`Python`脚本 44 | 45 | 在命令窗口运行,注意切换路径。 46 | 47 | `python hello.py` 48 | 49 | ### 以模块方式运行`Python`脚本 50 | 51 | ```python 52 | import hello 53 | hello.sayHello() 54 | ``` 55 | 56 | ### 模块路径 57 | 58 | 下载第三方模块时,注意要放到`site-packages`里。 59 | 60 | ## 包 61 | 62 | 一个包由多个模块组成,即有多个`.py`文件,这个包就是一个有层次的文件目录结构。 63 | 64 | 引入某个目录的模块,就是在该目录下放一个`__init__.py`文件。`__init__.py`文件是一个空白文件,可以将该目录下的`.py`文件作为模块引用。 65 | 66 | 创建包不是问了运行模块,而是为了导入模块使用,包知识模块的一种形式,可以简单地把包理解为模块。例如,包`A`和包`B`下有同名的模块`dao`,导入同名模块时就不会产生冲突。 67 | 68 | ### 导入包的方法 69 | 70 | ```python 71 | import moduleName.shortName 72 | # 这种方法要在__init__.py文件里设置 __all__ = ['modulename'] 73 | form modname import * 74 | ``` 75 | 76 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.2_random模块.md: -------------------------------------------------------------------------------- 1 | # random模块 2 | 3 | --- 4 | 5 | ### 功能 6 | 7 | 1. 取随机小数 8 | 2. 取随机整数:彩票,抽奖 9 | 3. 从一个列表中随机抽取值:抽奖 10 | 4. 打乱一个列表:洗牌 11 | 12 | ```python 13 | import random 14 | 15 | print(random.random()) # 取0-1之间的小数 16 | print(random.uniform(1,2)) # 取1-2之间的小数 17 | print(random.randint(1,2)) # [1-2]包含1和2 18 | print(random.randrange(1,2)) # [1,2)有1没有2 19 | print(random.randrange(1,200,2)) 20 | ``` 21 | 22 | ```python 23 | import random 24 | 25 | l = ['a','b',(1,2),123] 26 | print(random.choice(l)) # 随机抽取 27 | print(random.sample(l,2)) # 从列表中抽取两次 sample允许抽多次,不重复 28 | 29 | # 在原列表的基础上直接修改,节省空间 30 | random.shuffle(l) # 打乱原列表 31 | print(l) 32 | ``` 33 | 34 | ### 作业 35 | 36 | 生成随机验证码 37 | 38 | ```python 39 | import random 40 | 41 | # 数字验证码 42 | def code(n=6): 43 | s = '' 44 | for i in range(n): 45 | num = random.randint(0,9) 46 | s += str(num) 47 | return s 48 | 49 | print(code(4)) 50 | print(code()) 51 | 52 | # 数字和字母验证码 53 | def code(n=6): 54 | s = '' 55 | for i in range(n): 56 | # 生成随机的字母,数字各一个,再随机抽取 57 | num = str(random.randint(0,9)) 58 | alpha_upper = chr(random.randint(65,90)) # 大写范围 小写从97开始 59 | alpha_lower = chr(random.randint(97,122)) 60 | res = random.choice([num,alpha_upper,alpha_lower]) 61 | s += res 62 | return s 63 | 64 | print(code(4)) 65 | print(code()) 66 | 67 | # 前两个功能合并 68 | def code(n=6, alpha=True): 69 | s = '' 70 | for i in range(n): 71 | # 生成随机的字母,数字各一个,再随机抽取 72 | res = str(random.randint(0,9)) 73 | if alpha: 74 | alpha_upper = chr(random.randint(65,90)) # 大写范围 小写从97开始 75 | alpha_lower = chr(random.randint(97,122)) 76 | res = random.choice([res,alpha_upper,alpha_lower]) 77 | s += res 78 | return s 79 | 80 | print(code(4)) 81 | print(code()) 82 | ``` 83 | 84 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.3_sys模块.md: -------------------------------------------------------------------------------- 1 | ## `sys`模块 2 | 3 | --- 4 | 5 | 1. `sys`是和`python`计时器打交道 6 | 7 | 2. `sys.argv`的第一个参数是`python`这个命令后面的值 8 | 9 | 1. 程序员,运维人员在命令行运行代码 10 | 11 | 2. 操作系统陷入`input`事件,会退出CPU的竞争 12 | 13 | 3. 整个文件名路径不能有空格 14 | 15 | 4. 不支持中文(文件路径里不能有中文,符合变量命名规则) 16 | 17 | 5. 总结:当你在命令行执行`python`文件的时候,而不是在`pycharm`中执行, 18 | 19 | `>>>python python文件的路径 参数1 参数2 参数3` 20 | 21 | `sys.argv = ['python文件的路径', 参数1, 参数2, 参数3]` 22 | 23 | 好处:这些需要输入的参数不需要在程序中以`input`的形式输入 24 | 25 | 3. `sys.path`模块搜索路劲 26 | 27 | 1. 模块是存在硬盘上的,在使用时用`import`,导入内存 28 | 2. 一个模块能否被顺利的导入,全看`sys.path`下面有没有这个模块 29 | 3. 自定义模块导入时还需要关注`sys.path` 30 | 4. 是一个列表,这个列表存的都是文件夹的绝对路径 31 | 5. 如果一个模块导入不进来,把这个模块的文件夹添加到`sys.path`中 32 | 6. 内置模块和第三方模块安装之后不需要修改,操作,直接用 33 | 34 | 4. `sys.modules` 35 | 36 | 1. 所有被导入的模块的内存地址都存在`sys.modules`里 37 | 38 | ```python 39 | import sys 40 | import re 41 | 42 | print(sys.path) 43 | print(sys.modules) # 导入到内存中的所有模块的名字:这个模块的命名空间 44 | print(sys.modules['re'].findall('\d','abc126')) # 可以直接用 45 | ``` 46 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.4_JSON模块.md: -------------------------------------------------------------------------------- 1 | # JSON数据解析 2 | 3 | --- 4 | 5 | 如果要将一个程序内的数据通过网络传输给其他程序,通常需要先把这些数据转换为字符串。那么。需要按照一种统一的数据格式,才能让数据接收端正确解析字符串,并且理解这些数据的含义。XML是一种早先被广泛使用的数据交换格式,虽然XML可以作为跨平台的数据交换格式,但是使用XML格式存储的数据要比使用`JSON`格式存储的数据占用的空间大,增加了交换数据产生的流量。如今,越来越多的系统使用的数据交换格式是`JSON`,`JSON`相对于`XML`更加简单,易于理解和编写。 6 | 7 | ## `JSON`简介 8 | 9 | `JSON(JavaScript Object Notation)`是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。`JSON`采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯。这些特性使`JSON`称为理想的数据交换语言。 10 | 11 | 1. `JSON`名称/值对:`{"name":"Python"}` 12 | 2. `JSON`值:数字,字符串,逻辑值,数组,对象和null 13 | 3. `JSON`数组:`[]` 14 | 15 | ## Python处理`JSON`数据 16 | 17 | ```python 18 | # 序列化操作 19 | import json 20 | 21 | data = {'name':"wangwu",'lang':('python','java'), 'age':20} 22 | data_json = json.dumps(data) 23 | print(data) 24 | print(data_json) 25 | ``` 26 | 27 | ```python 28 | # 反序列化操作 29 | import json 30 | 31 | data = {'name':"wangwu",'lang':('python','java'), 'age':20} 32 | data_json = json.dumps(data) 33 | new_data = json.loads(data_json) 34 | print(new_data) 35 | ``` 36 | 37 | ## 自定义对象的序列化 38 | 39 | 如果是类对象,是不是可以直接用`json.dumps(obj)`序列化对象呢?答案是不可以的,需要在类对象中编写转换函数。 40 | 41 | ```python 42 | # 自定义对象的序列化 43 | import json 44 | 45 | 46 | class Man(object): 47 | def __init__(self, name, age): 48 | self.name = name 49 | self.age = age 50 | 51 | 52 | # 序列化函数 53 | def obj2json(obj): 54 | return { 55 | "name":obj.name, 56 | "age":obj.age 57 | } 58 | 59 | man = Man('tom', 21) 60 | jsonDataStr = json.dumps(man, default=obj2json) 61 | print(jsonDataStr) 62 | ``` 63 | 64 | ## 基本用法 65 | 66 | 1. 能够处理的数据类型是非常有限的:字符串,列表,字典,数字 67 | 68 | 2. 字典中的key只能是字符串 69 | 70 | 3. 在所有的语言之间都通用 71 | 72 | 4. `dumps/loads dump/load` 73 | 74 | 5. `json`是所有语言通用的一种序列化格式,只支持列表,字典,字符串,数字,字典的`key`必须是字符串 75 | 76 | - `dumps/loads`:在内存里处理 77 | 78 | - `dumps`数据类型转成字符串-->序列化 79 | 80 | - `loads`字符串转成数据类型-->反序列化 81 | 82 | `dump/load`:直接处理文件内容 83 | 84 | - `dump`数据类型写入文件-->序列化 85 | 86 | - `load`文件独处数据类型 --> 反序列化 87 | 88 | ```python 89 | import json 90 | 91 | dic = {'key':'value','key2':'value2'} 92 | ret = json.dumps(dic) # 序列化 93 | print(dic) 94 | print(ret) 95 | res = json.loads(ret) # 反序列化 96 | print(res) 97 | 98 | # 问题1:数字在转化过程中编程字符串 99 | dic = {1:'value',2:'value'} 100 | ret = json.dumps(dic) # 序列化 101 | print(dic) 102 | print(ret) 103 | res = json.loads(ret) # 反序列化 104 | print(res) 105 | 106 | # 问题2: 107 | dic = {1:[1,2,3],2:(4,5,'aa')} 108 | ret = json.dumps(dic) # 序列化 109 | print(dic) 110 | print(ret) 111 | res = json.loads(ret) # 反序列化 112 | print(res) 113 | 114 | # 问题3:不能序列化 115 | dic = {1,2,'aaa'} 116 | ret = json.dumps(dic) # 序列化 117 | print(dic) 118 | print(ret) 119 | res = json.loads(ret) # 反序列化 120 | print(res) 121 | 122 | # 问题4 123 | json.dumps({(1,2,3):123}) 124 | 125 | # 问题5 126 | # 可以多次dump,但是不能多次load,load文件中中能有一个字典 127 | ``` 128 | 129 | ```python 130 | # 写入和读取字典 131 | import json 132 | 133 | dic = {'key':'value','key2':'value2'} 134 | ret = json.dumps(dic) 135 | with open('json_file','a') as f: 136 | f.write(ret) 137 | with open('json_file','r') as f: 138 | str_dic = f.read() 139 | dic = json.loads(str_dic) 140 | print(dic) 141 | ``` 142 | 143 | ```python 144 | # 写入和读取字典 145 | import json 146 | 147 | dic = {'key':'value','key2':'value2'} 148 | with open('json_file','a') as f: 149 | json.dump(dic,f) 150 | with open('json_file','r') as f: 151 | dic = json.load(f) 152 | print(dic) 153 | ``` 154 | 155 | ```python 156 | import json 157 | 158 | dic = {'key':'value','key2':'value2'} 159 | with open('json_file','a') as f: 160 | str_dic = json.dumps(dic,f) 161 | f.write(str_dic+'\n') 162 | str_dic = json.dumps(dic,f) 163 | f.write(str_dic+'\n') 164 | str_dic = json.dumps(dic,f) 165 | f.write(str_dic+'\n') 166 | 167 | with open('json_file','r') as f: 168 | for line in f: 169 | dic = json.loads(line.strip()) 170 | print(dic) 171 | ``` 172 | 173 | ```python 174 | # 编码问题 175 | import json 176 | 177 | dic = {'key':'你好'} 178 | print(json.dumps(dic,ensure_ascii=False)) 179 | ``` 180 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.5_pickle模块.md: -------------------------------------------------------------------------------- 1 | # pickle模块 2 | 3 | --- 4 | 5 | Python是一种面向对象和面向过程的解释型程序设计语言。在Python中无论是变量还是函数都是一个对象,当Python脚本运行时,对象存储在内层中,随时等待系统的调用。但是内存中的对象数据会随着计算机关机而消失。在Pyton3中使用pickle膜对任意一种类型的Python对象进行序列化操作,如列表、字典和一个类的对象。pickle模块用于将Python对象存储到文件中,以及从文件中读取这些Python对象。 6 | 7 | ## 序列化对象 8 | 9 | ```python 10 | # 编码问题 11 | import pickle 12 | 13 | ls = [1, 2, 3, 4, 5] 14 | str = 'aaa' 15 | dict = { 16 | 'name':'wangwu' 17 | } 18 | 19 | class Book(object): 20 | def __init__(self, name, id): 21 | self.name = name 22 | self.id = id 23 | 24 | def __str__(self): 25 | return ('book name={0},id={1}'.format(self.name, self.id)) 26 | 27 | # 以二进制形式吧Python对象写入文件 28 | with open('ls.txt', 'wb') as f: 29 | pickle.dump(ls, f, 0) 30 | with open('str.txt', 'wb') as f: 31 | pickle.dump(ls, f, 0) 32 | with open('dict.txt', 'wb') as f: 33 | pickle.dump(ls, f, 0) 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.6_os模块.md: -------------------------------------------------------------------------------- 1 | # os模块 2 | 3 | --- 4 | 5 | 在Python中可以使用os模块来处理文件和目录。os模块不受平台限制,可以执行操作系统命令。 6 | 7 | ### os.popen()方法 8 | 9 | ```python 10 | import os 11 | 12 | # 查看当前目录下的文件 13 | data = os.popen('dir').read() 14 | print(data) 15 | ``` 16 | 17 | ### os.listdir()方法 18 | 19 | ```python 20 | import os 21 | 22 | # 产科D盘下的所有文件和目录的名称列表 23 | os.listdir('d:/') 24 | ``` 25 | 26 | ```python 27 | # 把D盘下所有可扩展名为.py的文件名写入d:/pylist.txt文件中 28 | import os 29 | 30 | pyList = os.listdir('d:/') 31 | fileName = 'd:/pylist.txt' 32 | file = open(fileName, 'w') 33 | 34 | for fileName in pyList: 35 | if fileName.endswith('.py'): 36 | file.write(fileName + '\n') 37 | else: 38 | file.close() 39 | ``` 40 | 41 | - 文件夹和文件的处理:创建/删除文件夹 重命名 删除文件 `listdir stat` 42 | - 路径的处理:路径拼接/拆分/计算大小/判断目录是否存在/是文件/是文件夹 绝对路径相关 43 | - 执行操作系统命令:执行路径相关 执行命令相关 44 | 45 | 1. 和操作系统打交道 46 | 2. `exec/eval`执行字符串数据类型的`python`代码,`os.popen()`执行字符串数据类型的操作系统代码 47 | 3. 创建和删除空文件夹 48 | 4. 文件的重命名和删除 49 | 5. 查看当前目录下的所有文件和文件 50 | 6. `stat`获得文件信息 51 | 7. `system popen getcwd chdir` 52 | 8. `os.path.join`拼接目录 53 | 9. 定制了很多方法,间接地帮助你去调用操作系统的命令,也可以用`os.popen/os.system`直接调用操作系统的命令,如果`os`模块解决不了需求时,可以用`os.popen/os.system`来解决 54 | 55 | ![os模块](D:\repository\PythonNotes\notes\第3章 Python语法\images\os模块.png) 56 | 57 | ```python 58 | # 有问题。。。。。 59 | import os 60 | 61 | os.makedirs('dir1/dir2') 62 | os.mkdir('dir3') # 只能创建一个 63 | os.mkdirs('dir3/dir4') # 创建多个文件夹 64 | # 只能删空文件夹 65 | os.rmdir('dir3/dir4') 66 | os.removeddirs('dir3/dir4') 67 | 68 | # 拿到目录 69 | file_list = print(os.listdir('D:\sylar\s15')) 70 | for path in file_list: 71 | print(os.path.join(['D:\sylar\s15',path])) 72 | ``` 73 | 74 | ```python 75 | import os 76 | 77 | os.system('dir') # 执行操作系统的命令,没有返回值,适合实际的操作:删除文件,创建文件夹 78 | 79 | ret = os.popen('dir') # 执行字符串,适合做查看类的操作 80 | print(ret.read()) 81 | 82 | print(os.getcwd()) # 当前工作目录,并不是指当前文件所在目录,而是当前文件是在哪个目录下执行 83 | os.chdir('...') # 切换当前工作目录 84 | ``` 85 | 86 | ```python 87 | import os 88 | 89 | os.path.abspath() 90 | path = os.path.split('路径') # 把一个路径分成两段,第二段是一个文件或文件夹 91 | print(path) 92 | ret1 = os.path.dirname('路径') 93 | ret2 = os.path.basename('路径') 94 | print(ret1) 95 | print(ret2) 96 | 97 | # 判断文件/文件夹是否存在 98 | res = os.path.exists('路径') 99 | print(res) 100 | 101 | # 怕短是否为绝对路径 102 | res = os.path.isabs('路径') 103 | print(res) 104 | 105 | # 判断是否为文件夹/文件 106 | print(os.path.isdir('路径')) 107 | print(os.path.isfile('路径')) 108 | 109 | # 拼接路径 110 | os.path.join('路径','aaa') 111 | 112 | # 查看文件大小 113 | size = os.path.getsize('路径') 114 | print(size) 115 | ret1 = os.path.getsize('文件夹') 116 | ret2 = os.path.getsize('文件夹') 117 | print(ret1, ret2) 118 | # 所有的文件夹都至少是4096个字节,也可能是8192 119 | #无法使用python代码统计一个文件夹中所有文件的总大小 120 | ``` 121 | 122 | 同步过程:通过访问文件的最后修改时间判断是否同步更新 123 | 124 | ![电脑间的同步原理](D:\repository\PythonNotes\notes\第3章 Python语法\images\电脑间的同步原理.png) 125 | 126 | 操作系统和`python` 127 | 128 | ![操作系统和python](D:\repository\PythonNotes\notes\第3章 Python语法\images\操作系统和python.png) 129 | 130 | 计算文件夹的内存 131 | 132 | ```python 133 | import os 134 | 135 | # 递归版本 136 | def func(path): 137 | size_sum = 0 138 | name_lst = os.listdir(path) 139 | for name in name_lst: 140 | path_abs = os.path.join(path, name) 141 | if os.path.exists(path_abs): 142 | if os.path.isdir(path_abs): 143 | size = func(path_abs) 144 | size_sum += size 145 | else: 146 | size_sum += os.path.getsize(path_abs) 147 | return size_sum 148 | 149 | 150 | ret = func(r'D:\repository\PythonNotes') 151 | print(ret) # 统计的结果不是完全相同的(windows系统)-->文件碎片 152 | 153 | # 循环 堆栈思想 154 | # 列表满足一个顺序,先进来的后出去 155 | l = [r'D:\repository\PythonNotes'] 156 | size_sum = 0 157 | while l: 158 | path = l.pop() # path = '路径' l = [] 159 | path_list = os.listdir(path) 160 | for name in path_list: 161 | abs_path = os.path.join(path, name) 162 | if os.path.isdir(abs_path): 163 | l.append(abs_path) # 再次添加文件夹里的文件夹 164 | else: 165 | size = os.path.getsize(abs_path) 166 | size_sum += size 167 | 168 | print(size_sum) 169 | ``` 170 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.7_time模块.md: -------------------------------------------------------------------------------- 1 | # time模块 2 | 3 | --- 4 | 5 | ### 功能 6 | 7 | 1. 主要用来和时间打交道 8 | 2. 时间格式 9 | 1. 浮点型数据类型:以秒为单位`1534732642.617272` 10 | 2. 结构化时间:元组,只能取值不能修改 11 | 3. 格式化数据类型`2020-01-02` `%Y %m %d %H %M %S` 12 | 13 | 3. 计算机时间`1970-01-01 00:00:00 ` 14 | 4. 三种时间的转换 15 | 16 | ![time模块三种时间格式转换](D:\repository\PythonNotes\notes\第3章 Python语法\images\time模块三种时间格式转换.png) 17 | 18 | ```python 19 | import time 20 | 21 | time.sleep(2) 22 | print(123) 23 | print(time.time()) 24 | print(time.strftime('%Y-%m-%d %H:%M:%S')) 25 | print(time.strftime('%c')) # 英国人格式 26 | print(time.localtime()) # 结构化时间 27 | 28 | struct_time = time.localtime() 29 | print(struct_time.tm_mon) 30 | ``` 31 | 32 | ```python 33 | import time 34 | 35 | # 时间戳-->结构化 36 | print(time.time()) 37 | print(time.localtime(1500000000)) # 北京时间 38 | print(time.gmtime(1500000000)) # 伦敦时间 39 | 40 | # 结构化-->字符串 41 | struct_time = time.localtime(1500000000) 42 | ret = time.strftime('%Y-%m-%d %H:%M:%S', struct_time) 43 | print(ret) 44 | 45 | # 字符串-->结构化 46 | struct_time = time.strptime('2018-8-8','%Y-%m-%d') 47 | print(struct_time) 48 | 49 | # 结构化-->时间戳 50 | res = time.mktime(struct_time) 51 | print(res) 52 | ``` 53 | 54 | ### 练习 55 | 56 | 1. 查看`200000000`时间戳对应的年月日 57 | 58 | ```python 59 | import time 60 | 61 | struct_time = time.localtime(2000000000) 62 | ret = time.strftime('%Y:%m:%d', struct_time) 63 | print(ret) 64 | ``` 65 | 66 | 2. 请将当前时间的当前月1号的时间戳时间取出来 67 | 68 | ```python 69 | import time 70 | 71 | def get_time(): 72 | st = time.localtime() 73 | st1= time.strptime('%s-%s-%s' % (st.tm_year, st.tm_mon, st.tm_mday), '%Y-%m-%d') 74 | return time.mktime(st1) 75 | 76 | print(get_time()) 77 | ``` 78 | 79 | 3. 计算时差 80 | 81 | ```python 82 | import time 83 | 84 | str_time1 = '2018-08-19 22:10:8' 85 | str_time2 = '2018-08-20 11:07:3' 86 | struct_t1 = time.strptime(str_time1, '%Y-%m-%d %H:%M:%S') 87 | struct_t2 = time.strptime(str_time2, '%Y-%m-%d %H:%M:%S') 88 | timestamp1 = time.mktime(struct_t1) 89 | timestamp2 = time.mktime(struct_t2) 90 | sub_time = timestamp2 - timestamp1 91 | gm_time = time.gmtime(sub_time) 92 | print( 93 | '过去了%d年%d月%d日%d小时%d分钟%d秒' % ( 94 | gm_time.tm_year-1970, 95 | gm_time.tm_mon-1, 96 | gm_time.tm_yday, 97 | gm_time.tm_hour, 98 | gm_time.tm_min, 99 | gm_time.tm_sec)) 100 | ``` 101 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.8_正则表达式.md: -------------------------------------------------------------------------------- 1 | # 正则表达式 2 | 3 | >推荐书籍:`python`语言使用正则表达式 4 | 5 | --- 6 | 7 | ## 什么是正则表达式 8 | 9 | 是一种独立的规则,独立的语言;从大段文字中找到符合规则的内容;正则表达式之和字符串打交道。正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。 10 | 11 | ## 能用来做什么 12 | 13 | **爬虫**:从网页的字符串中获取你想要的数据 14 | 15 | **日志分析**:提取各种行为数据进行分析 16 | 17 | 1. 什么是日志:记录具体的行为,包括时间,行为,消费情况等 18 | 19 | **表单验证**:验证手机号,身份证号等是否书写正确 20 | 21 | ## 正则表达式的规则 22 | 23 | 1. 字符组:`[]`写在中括号中的内容都出现在下面的某一个字符的位置上,都是符合规则的 24 | 25 | 要根据`ascii`码大小顺平,从小往大 26 | 27 | 1. `[0-9]`匹配数字 28 | 2. `[a-z]`匹配小写字母 29 | 3. `[A-Z]`匹配大写字母 30 | 4. `[a-zA-Z]`匹配大小写字母 31 | 5. `[0-9a-zA-Z_]`数字字母下划线 32 | 33 | 2. 转义符`\` 34 | 35 | 1. 单个`\`用来转义 36 | 2. 要匹配没有转义的`\`需要有偶数`\` 37 | 38 | 3. 元字符`(15个)` `\w \d \s \n \t \b \W \D \S` 39 | 40 | 1. 和转义相关 41 | 1. `\w`匹配数字,字母和下划线 42 | 2. `\d`匹配数字 43 | 3. `\s`匹配所欲的空白符:空格,换行符`\n`,制表符`\t` 44 | 4. `\W,\D,\S`匹配与小写功能相反 45 | 5. `[\s\S] [\w\W] [\d\D]`匹配所有内容 46 | 6. `\b`表示单词的边界 47 | 48 | 2. 和转义无关 49 | 50 | 1. `^`表示匹配一个字符串的开始 51 | 2. `$`表示匹配一个字符串的结尾 52 | 53 | 3. 其他 54 | 55 | 1. `.`匹配除换行符之外的所欲字符 56 | 57 | 2. `[^ ]`只要不出现中括号中的内容就能被匹配,`^`必须卸载最前面 58 | 59 | 1. 有一些特殊意义的元字符进入字符组中会恢复他本来的意义 60 | 61 | `. | [不能成对出现] ( ) 量词`取消了特殊意义 62 | 63 | `-`在中括号中有特殊意义,用作减号需要转义 64 | 65 | 3. `a|b`或 66 | 67 | 1. 符合a规则的或者b规则的都可以被匹配 68 | 2. 如果a规则是b规则的一部分,且a规则比b规则要苛刻,就把a规则写在前面 69 | 3. 将更复杂的规则写在前面 70 | 71 | 4. `()`分组 72 | 73 | 1. 表示给几个字符加上量词约束的需求时,就给这些量词分在一组 74 | 75 | ```python 76 | # 匹配手机号 77 | 1[3-9]\d{9} 78 | ``` 79 | 80 | 4. 量词 81 | 82 | 1. `{n}`表示这个量词之前的字符出现n次 83 | 2. `{n,}`表示这个量词之前的字符至少出现n次 84 | 3. `{n,m}`表示这个量词出现`n-m`次 85 | 4. `?`匹配出现0次或1次,表示可有可无 86 | 5. `+`匹配出现1次或多次 87 | 6. `*`匹配0次到多次 88 | 89 | ```python 90 | # 匹配小数或者整数 91 | \d+\.\d+|\d+ 92 | \d+(\.\d+)? 93 | ``` 94 | 95 | 5. 贪婪匹配/懒惰匹配 96 | 97 | 1. 贪婪匹配 98 | 1. 在允许的范围内取最长的内容 99 | 100 | 2. 默认贪婪匹配 101 | 102 | ![贪婪模式](D:\repository\PythonNotes\notes\第3章 Python语法\images\贪婪模式.png) 103 | 104 | 2. 懒惰模式 105 | 106 | 1. 在**量词**的后面加上一个`?` 107 | 108 | 2. 在范围内尽量少的匹配 109 | 110 | 3. `.*?x`匹配任意非换行符字符,任意长度,直到遇到x就停止 111 | 112 | 4. `李.??和` 113 | 114 | 1. `.`是元字符,匹配任意非换行字符 115 | 2. 第一个`?`是量词,表示匹配`0-1`次 116 | 3. 第二个`?`是约束惰性匹配的标志,报送`.`的匹配应该尽可能少匹配 117 | 4. 后面的`和`约束力`.`的匹配必须多匹配一个`杰`,否则就没有匹配结果了 118 | 5. 两个问号表示在可能匹配的基础上尽可能少匹配 119 | 120 | ![懒惰模式](D:\repository\PythonNotes\notes\第3章 Python语法\images\懒惰模式.png) 121 | 122 | 123 | ## 练习 124 | 125 | ```python 126 | # 匹配15位或18位身份证号码 127 | [1-9]\d{16}[\dX]|[1-9]\d{14} # 只能匹配一行里的内容 128 | [1-9]\d{14}(\d{2}[\dX])? 129 | ``` 130 | 131 | ## 作业 132 | 133 | 1. 匹配整数或者小数(包括整数和负数) 134 | 135 | ```python 136 | -?\d+(\.\d+)? 137 | ``` 138 | 139 | 2. 匹配年月日日期,格式`2018-12-6` 140 | 141 | ```python 142 | [1-9]\d{3}-([1][0-2]|0?[1-9])-(3[01]|[12]\d|0?[1-9]) 143 | ``` 144 | 145 | 3. 匹配`qq`号 146 | 147 | ```python 148 | [1-9]\d{4, 11} 149 | ``` 150 | 151 | 4. 11位电话号码 152 | 153 | ```python 154 | 1[3-9]\d{9} 155 | ``` 156 | 157 | 5. 匹配`8-10`位用户密码,包含数字字母下划线 158 | 159 | ```python 160 | \w{8, 10} 161 | ``` 162 | 163 | 6. 匹配验证码:4位数字字母组成 164 | 165 | ```python 166 | [\da-zA-Z]{4} 167 | ``` 168 | 169 | 7. 匹配邮箱地址 170 | 171 | ```python 172 | [0-9a-zA-Z][\w\-.]+@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*\.[A-Za-z0-9]{2,6} 173 | ``` 174 | 175 | 8. `wahaha` 176 | 177 | ```python 178 | >\w+< 179 | \w{6} 180 | # 先匹配,再用python修改 181 | ``` 182 | 183 | 9. `1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))`从上式中匹配内层无小括号这层的内容加括号 184 | 185 | ```python 186 | \([^()]+\) 187 | ``` 188 | 189 | 10. 从类似`9-2*5/3+7/3*99/4*2998+10*568/14`的表达式中匹配除从左到右第一个乘法或除法 190 | 191 | ```python 192 | # 匹配的有问题 193 | \d+[*/]\d+ 194 | ``` 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.3_模块和包/2.2.3.9_re模块.md: -------------------------------------------------------------------------------- 1 | # re模块 2 | 3 | --- 4 | 5 | ## 基础方法 6 | 7 | 1. 永远不要起一个`py`文件的名字,或者与模块和函数同名的名字 8 | 9 | 2. 查找:`findall search match` 10 | 11 | 1. `findall`匹配所有每一项都是列表中的一个元素,返回列表 12 | 2. `search`只匹配从左到右第一个,得到的不是直接结果,通过`re.group()`获取结果。如果没有匹配到,会返回`None`,使用`group`会报错 13 | 3. `match`从头开始匹配,相当于`search`中的正则表达式加上一个`^`,必须开头符合规则才有匹配结果 14 | 15 | 3. 字符串处理:`split sub subn` 16 | 17 | 1. `split`返回列表,按正则规则切割,默认匹配到的内容会被切割 18 | 2. `sun/subn`替换,按照正则规则去寻找要被替换的内容,`subn`返回元组,第二个值是替换的次数 19 | 20 | 4. `re`模块的进阶:`compile finditer` 21 | 22 | `compile`节省使用正则表达式解决问题的时间。把正则表达式编译成字节码,在多次使用的过程中不会多次编译 23 | 24 | ```python 25 | import re 26 | ret = re.compile('\d+') # 已经完成编译,节省时间 27 | res = ret.search('ewf334dfji5123') 28 | print(res) # 会打印出详细信息 29 | print(res.group()) # 打印出匹配的结果 30 | ``` 31 | 32 | ​ `finditer`节省使用正则表达式解决问题的空间/内存。返回一个迭代器,所有的结果都在这个迭代器中,需要通过循环加`group`形式取值,节省内存 33 | 34 | ```python 35 | import re 36 | ret = re.finditer('\d+', 'ewf334dfji5123') 37 | print(ret) 38 | for i in ret: 39 | print(i.group()) 40 | ``` 41 | 42 | ```python 43 | import re 44 | 45 | ret = re.findall('\d+', 'ewf334dfji5123') # 正则表达式,带匹配的字符串,flag 46 | ret1 = re.findall('\d', 'ewf334dfji5123') 47 | print(ret) 48 | print(ret1) 49 | 50 | ret = re.search('\d+', 'ewf334dfji5123') 51 | print(ret) # 返回内存地址,只是一个正则匹配的结果 52 | print(ret.group()) # 通过re.group()返回匹配结果 53 | 54 | ret = re.search('\d', 'ewfdfji') 55 | if ret: 56 | print(ret.group()) 57 | 58 | ret = re.match('\d+', 'ewf334dfji5123') 59 | # 相当于ret = re.search('^\d+','ewf334dfji5123') 60 | print(ret) 61 | ``` 62 | 63 | ```python 64 | import re 65 | 66 | s = 'alex83taibai40egon25' 67 | ret = re.split('\d+', s) 68 | print(ret) 69 | 70 | # 最后的1表示替换的次数 71 | ret = re.sub('\d+','H',s, 1) 72 | print(ret) 73 | 74 | # 返回元组,第二个元素是替换的次数 75 | ret = re.subn('\d+','H',s) 76 | print(ret) 77 | ``` 78 | 79 | ![re模块](D:\repository\PythonNotes\notes\第3章 Python语法\images\re模块.png) 80 | 81 | ## 在`python`中使用正则表达式的特点和问题 82 | 83 | 1. 关于分组 84 | 1. 对于正则表达式来说,有些时候我们需要进行分组,来整体约束某一组字符出现的次数。 85 | 2. 对于`python`来说,分组可以帮助你更好更精确的找到你真正需要的内容 86 | 3. 用于优先显示分组 87 | 88 | ```python 89 | import re 90 | 91 | s = 'wahaha' # 标签语言 html 和web息息相关 92 | ret = re.search('(>)(\w+)(<)', s) 93 | print(ret.group(0)) # 所有结果 94 | print(ret.group(1)) 95 | print(ret.group(2)) 96 | print(ret.group(3)) 97 | ret = re.search('<(\w+)>(\w+)<(/\w+)>', s) 98 | print(ret.group(1)) 99 | print(ret.group(2)) 100 | print(ret.group(3)) 101 | 102 | # 为了findall也可以顺利取到分组中的内容,有一个特殊的语法,就是优先显示分组中的内容 103 | ret1 = re.findall('>\w+<', s) 104 | ret2 = re.findall('>(\w+)<', s) 105 | print(ret1) 106 | print(ret2) 107 | 108 | ret = re.findall('\d+(\.\d+)?','1.234*2.123') 109 | print(ret) 110 | # 取消分组优先 111 | ret = re.findall('\d+(?:\.\d+)?','1.234*2.123') 112 | print(ret) 113 | ``` 114 | 115 | ```python 116 | import re 117 | 118 | # 切割 119 | ret1 = re.split('(\d+)', 'alex83taibai40egon25') 120 | print(ret1) 121 | ``` 122 | 123 | 2. 分组命名`(?P<这个组的名字>正则表达式)` 124 | 125 | ```python 126 | import re 127 | 128 | s = 'wahaha' 129 | ret = re.search('>(?P\w+)<', s) 130 | print(ret.group(1)) 131 | print(ret.group('content')) 132 | ``` 133 | 134 | ```python 135 | import re 136 | 137 | # 判断网页标签格式是否正确 138 | s = 'wahaha' 139 | pattern = '<(?P\w+)>(\w+)' 140 | ret = re.search(pattern, s) 141 | print(ret) 142 | ``` 143 | 144 | ## 使用正则表达式的技巧 145 | 146 | 1. 你要匹配的内容太没有特点,容易和你不想匹配的内容混在一起,精准的取到整数,过滤小数 147 | 2. 正则表达式如果写的足够好的话,能够最大限度的简化我们的操作 148 | 3. 至少掌握作业中的内容,能够看懂常用的正则表达式,并且能够做出一些公司特异性要求的修改 149 | 150 | ```python 151 | import re 152 | 153 | ret = re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))") 154 | # 从1-2*(60+(-40.35/5)-(-4*3))中取整数 155 | print(ret) 156 | 157 | ret = re.findall(r"\d+\.\d+|\d+","1-2*(60+(-40.35/5)-(-4*3))") 158 | # 把整数小数都匹配出来 159 | print(ret) 160 | 161 | ret = re.findall(r"(\d+\.\d+)|(\d+)","1-2*(60+(-40.35/5)-(-4*3))") 162 | ret.remove('') # 没有实现 163 | print(ret) 164 | ``` 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.4_多任务编程/2.2.4.1_多线程.md: -------------------------------------------------------------------------------- 1 | # 多线程 2 | 3 | --- 4 | 5 | ## 多任务的介绍 6 | 7 | 1. 提问 8 | 9 | 利用现学知识能够让两个函数或者方法同时执行么? 10 | 11 | 不能。因为之前缩写的程序都是单任务的,也就是说一个函数或者方法执行完成另外一个函数或者方法才能执行,要想实现这种操作就需要使用多任务。多任务的最大好处是充分利用CPU资源,提高程序的执行效率。 12 | 13 | 2. 多任务的概念 14 | 15 | 多任务是指在同一时间执行多个任务。例如,现在电脑安装的操作系统都是执行多人操作系统,可以同时运行多个软件。 16 | 17 | 3. 多任务的执行方式 18 | 19 | - 并发 20 | - 并行 21 | 22 | 并发:在一段时间内交替执行任务 23 | 24 | 并行:对于多核CPU处理多任务,操作系统会给CPU的每个内核安排一个执行的软件。多个内核是真正的一起执行软件。智力需要注意多核CPU是并行的执行多任务,始终有多个软件一起执行。 25 | 26 | 4. 总结 27 | 28 | 任务数大于CPU的核数是并发执行,小于是并行执行。 29 | 30 | ## 多线程介绍 31 | 32 | 线程有时被称为轻量进程,是程序执行流的最小单元。一个标准的线程由线程ID,当前计算机的指令指针,寄存器集合和堆栈组成。线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程不拥有私有的系统资源,但它可与同属一个进程的其他线程共享所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一进程中的多个线程之间可以并发执行。 33 | 34 | 线程是程序中一个单一 的顺序控制流程。进程内有一个相对独立的、可调度的执行单元,是系统 独立调度和分派CPU的基本单位指令运行时的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,被称为多线程。Python多线程用于`I/O`操作密集型的任务,如`SocketServer`网络并发、网络爬虫。 35 | 36 | 现代处理器都是多核的,几核处理器只能同时处理几个线程,多线程执行程序看起来是同时运行,实际上是CPU在多个线程之间快速切换执行,这中间就涉及了上下文切换。所谓的上下文切换,就是指一个线程Thread被分配的时间片用完后,线程的信息被保存起来,CPU执行另外一个线程,再到CPU读取线程Thread的信息并继续执行Thread的过程。 37 | 38 | ## 多线程模块`threading` 39 | 40 | ### 参数说明: 41 | 42 | - `target`是函数名称,需要调用的函数 43 | - `name`设置线程名称 44 | - `args kwargs`函数需要的参数,以元组或字典的形式传入 45 | - `run()`用以表示线程获得的方法 46 | - `start()`启动线程 47 | - `join()`等待线程中止 48 | - `isAlive()`返回线程是否获得 49 | - `getName()`返回线程名称 50 | - `setName()`设置线程名称 51 | 52 | ### 函数式创建线程 53 | 54 | ```python 55 | import threading 56 | import time, random, math 57 | 58 | 59 | def printNum(idx): 60 | for num in range(idx): 61 | print(f'{threading.current_thread().getName()}\tnum={num}') 62 | # math.ceil 向上取整数 63 | delay = math.ceil(random.random() * 2) 64 | time.sleep(delay) 65 | 66 | 67 | if __name__ == '__main__': 68 | th1 = threading.Thread(target=printNum, args=(2,), name='thread1') 69 | th2 = threading.Thread(target=printNum, args=(3,), name='thread2') 70 | # 启动线程 71 | th1.start() 72 | th2.start() 73 | # 等待至线程中止,这里可以设置等待时间 74 | th1.join() 75 | th2.join() 76 | print(f'{threading.current_thread().getName()} 线程结束') 77 | ``` 78 | 79 | ### 创建线程类 80 | 81 | ```python 82 | import threading 83 | import time, random, math 84 | 85 | class MultiThread(threading.Thread): 86 | def __init__(self, threadName, num): 87 | # 这里要初始化threading模块 88 | threading.Thread.__init__(self) 89 | self.name = threadName 90 | self.num = num 91 | 92 | def run(self): 93 | for i in range(self.num): 94 | print(f'{threading.current_thread().getName()}\tnum={self.num}') 95 | delay = math.ceil(random.random() * 2) 96 | time.sleep(delay) 97 | 98 | 99 | if __name__ == '__main__': 100 | thr1 = MultiThread('thread1', 3) 101 | thr2 = MultiThread('thread2', 2) 102 | 103 | thr1.start() 104 | thr2.start() 105 | 106 | thr1.join() 107 | thr2.join() 108 | print(f'{threading.current_thread().getName()} 线程结束') 109 | ``` 110 | 111 | ## 守护线程 112 | 113 | 在多线程开发中,如果子线程设定为守护线程,则会在等待主线程运行完毕后被销毁。一个主线程可以设置多个守护线程。守护线程运行的前提是主线程必须存在,如果主线程不存在了,守护线程就会被销毁。 114 | 115 | ```python 116 | import threading, time 117 | 118 | 119 | def run(taskName): 120 | print('任务:', taskName) 121 | time.sleep(2) 122 | print(f'{taskName}任务执行完毕') 123 | 124 | 125 | if __name__ == '__main__': 126 | start_time = time.time() 127 | for i in range(3): 128 | thr = threading.Thread(target=run, args=(f'task-{i}',)) 129 | # 把子线程设置为守护线程 130 | thr.setDaemon(True) 131 | thr.start() 132 | 133 | print(f'{threading.current_thread().getName()}线程结束,当前线程数量={threading.active_count()}') 134 | print(f'消耗时间:{time.time() - start_time}') 135 | ``` 136 | 137 | ## 多线程的锁机制 138 | 139 | 多线程编程访问共享变量时会出现问题,但是多进程编程访问共享变量不会出现问题。因为多进程中,同一个变量自有一份存于每个进程中,互不影响;而多线程中,所有变量都由所有线程共享。多个进程之间对内存中的变量不会产生冲突,一个进程由多个线程组成。多线程对内存中的变量进行共享时产生影响,导致产生死锁问题。 140 | 141 | ```python 142 | import threading 143 | 144 | 145 | balance = 100 146 | # 设置锁 147 | lock = threading.Lock() 148 | 149 | def change(num, counter): 150 | global balance 151 | for i in range(counter): 152 | # 获取锁 153 | lock.acquire() 154 | balance += num 155 | balance -= num 156 | # 释放锁 157 | lock.release() 158 | 159 | if balance != 100: 160 | print(f'balance={balance}') 161 | break 162 | 163 | 164 | if __name__ == '__main__': 165 | thr1 = threading.Thread(target=change, args=(100, 50000), name='t1') 166 | thr2 = threading.Thread(target=change, args=(100, 50000), name='t2') 167 | thr1.start() 168 | thr2.start() 169 | thr1.join() 170 | thr2.join() 171 | print(f'{threading.current_thread().getName()}线程结束') 172 | ``` 173 | 174 | 扩展:默认GIL锁在执行100个`cpu`指令(过期时间)。 175 | 176 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.4_多任务编程/2.2.4.2_多进程.md: -------------------------------------------------------------------------------- 1 | # 多进程 2 | 3 | --- 4 | 5 | ## 多进程的使用 6 | 7 | 学习目标 8 | 9 | - 能够使用多进程完成多任务 10 | 11 | --- 12 | 13 | 1. 导入进程包 14 | 15 | `import multiprocessing` 16 | 17 | 2. Process进程类的说明 18 | 19 | ![process进程类的说明](D:\repository\PythonNotes\notes\第3章 Python语法\images\process进程类的说明.png) 20 | 21 | 3. 多进程完成多任务的代码 22 | 23 | ```python 24 | import multiprocessing 25 | import time 26 | import os 27 | 28 | def dance(): 29 | for i in range(3): 30 | print('跳舞中。。。') 31 | time.sleep(0.2) 32 | 33 | def sing(): 34 | for i in range(3): 35 | print('唱歌中。。。') 36 | time.sleep(0.2) 37 | 38 | if __name__ == '__main__': 39 | main_process_id = os.getpid() 40 | print('main_process:', main_process_id, multiprocessing.current_process()) 41 | dance_process = multiprocessing.Process(target=dance, name='dance_process') 42 | print('dance_process:', dance_process) 43 | sing_process = multiprocessing.Process(target=sing, name='sing_process') 44 | print('sing_process:', sing_process) 45 | # 执行顺序不确定 46 | dance_process.start() 47 | sing_process.start() 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/2.2_Python进阶/2.2.5_软件开发规范.md: -------------------------------------------------------------------------------- 1 | # 软件开发规范 2 | 3 | --- 4 | 5 | ![软件开发规范](D:\repository\PythonNotes\notes\第3章 Python语法\images\软件开发规范.png) 6 | 7 | `bin`运行脚本程序`core`核心程序`db`数据存储 8 | 9 | `lib`表示库,非内置或第三方库,自己写的比较完善的功能,还和当前项目的相关性不大,通用功能 10 | 11 | `conf`配置文件,用到了某一个值,这个值在程序执行的过程中会被修改,且一旦修改了需要修改多出代码,那么这样的值应该单独的写在`conf`文件夹下的一个文件中,来保证以后所有的程序重置这个值时,都需要从这个文件中读取,在需要修改这个值时只需要修改配置文件中的一处就可以了。能够方便运维的使用和维护。 12 | -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/Guido Van Rossum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/Guido Van Rossum.jpg -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/Unicode-utf8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/Unicode-utf8.jpg -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/Unicode-浏览器.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/Unicode-浏览器.jpg -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/and_or.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/and_or.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/hash讲解.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/hash讲解.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/os模块.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/os模块.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/process进程类的说明.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/process进程类的说明.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/re模块.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/re模块.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/time模块三种时间格式转换.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/time模块三种时间格式转换.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/五星红旗.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/五星红旗.jpg -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/函数定义说明文档.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/函数定义说明文档.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/分支条件公式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/分支条件公式.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/异常处理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/异常处理.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/异常处理过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/异常处理过程.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/懒惰模式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/懒惰模式.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/操作系统和python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/操作系统和python.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/数据的可变和不可变.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/数据的可变和不可变.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/数据类型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/数据类型.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/正方形.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/正方形.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/浅拷贝.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/浅拷贝.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/深拷贝.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/深拷贝.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/电脑间的同步原理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/电脑间的同步原理.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/类中的self.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/类中的self.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/贪婪模式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/贪婪模式.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/软件开发规范.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/软件开发规范.png -------------------------------------------------------------------------------- /notes/第2章 Python基础/images/集合.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第2章 Python基础/images/集合.png -------------------------------------------------------------------------------- /notes/第3章 MySQL数据库/3.1_MySQL简介.md: -------------------------------------------------------------------------------- 1 | # MySQL简介 2 | 3 | --- 4 | 5 | MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle旗下产品。MySQL是最流行的关系型数据库管理系统之一,在Web应用方面,MySQL是最好的的应用软件。关系型数据库是将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就提高了速度增加了灵活性。 6 | 7 | MySQL所使用的SQL语言是用于访问数据库最常用的标准语言。MySQL软件采用了双授权政策,分为社区版和商业版。由于其体积小、速度快、总体拥有成本低,尤其是开放源代码这一特点,一般中小型网站的开发都选择MySQL作为网站数据库。 8 | 9 | MySQL数据库遵循事务的ACID规则。事务在英文中是Transaction,与现实世界中的交易很类似,它有以下四个特征。 10 | 11 | ## 原子性Atomicity 12 | 13 | 事务中的所有操作要么全部执行,要么全部拒绝,没有任何中间状态。也就是说,事务中的所有操作要么全部完成,要么不做。事务成功的条件也是事务中的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。 14 | 15 | 如银行转账,从A账户转100元到B账户,分为以下两个步骤。 16 | 17 | 1. 从A账户去100元 18 | 2. 存入100元到B账户。这两步要么一起完成,要么一起不完成。如果只完成第一步,第二步失败,那么前就会莫名其妙少100元。 19 | 20 | ## 一致性Consistency 21 | 22 | 数据库的完整性约束不会被任何事务破坏,也就是说,数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。 23 | 24 | 例如,现有完整性约束`a + b = 10`,如果一个事务a改变了,那么必须要改变另一个事务b,使得事务结束后依然满足`a + b = 10`,否则事务失败。 25 | 26 | ## 隔离性Isolation 27 | 28 | 多个事务完全被隔离开来,一个事务的执行不会被其他事务影响。隔离性是指并发的事务之间不会相互影响,如果一个事务要访问的数据正在被另一个事务修改,只要另一个书屋为提交,它所访问的数据就不受未提交事务的影响。 29 | 30 | 例如,现在有一个交易是从A账号转入100元到B账号,在这个交易还未完成的情况下,如果此时B长自己的账号,是看不到新增加的100元。 31 | 32 | ## 持久性Durability 33 | 34 | 一个事务完成后,改事务对数据库的变更会被永久的存在数据库。持久性是指一旦事务提交后,它所做的修改将永久的保存在数据库中,即使出现宕机也不好丢失。 35 | 36 | -------------------------------------------------------------------------------- /notes/第3章 MySQL数据库/3.2_MySQL安装.md: -------------------------------------------------------------------------------- 1 | MySQL压缩包安装 2 | 3 | --- 4 | 5 | - 官网下载压缩包:https://dev.mysql.com/downloads/mysql/ 6 | 7 | - 解压后,在解压路径及bin文件配置环境变量 8 | 9 | - 配置`my.ini`文件放在安装目录下 10 | 11 | ```python 12 | [mysqld] 13 | # 设置MySQL的端口号为3306 14 | port = 3306 15 | # 设置MySQL的安装目录,需要双斜杠,需要双斜杠,需要双斜杠 16 | basedir=D:\\software\\mysql\\mysql-8.1.0-winx64 17 | # 设置MySQL数据库的数据存放目录,需要双斜杠,需要双斜杠,需要双斜杠 18 | datadir=D:\\software\\mysql\\mysql-8.1.0-winx64\\data 19 | # 允许最大连接数 20 | max_connections=200 21 | # 服务端使用的字符集默认为8比特编码的latin1字符集,这里将字符集设置为utf-8 22 | character-set-server=utf8 23 | # 创建新表时将使用的默认存储引擎 24 | default-storage-engine=INNODB 25 | # 创建模式 26 | sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 27 | 28 | [mysql] 29 | 30 | # 设置mysql客户端默认字符集 31 | default-character-set=utf8 32 | ``` 33 | 34 | - 运用管理员身份在`cmd`中进行安装 35 | 36 | ```python 37 | # 调整路径 38 | D: 39 | cd D:\software\mysql\mysql-8.1.0-winx64 40 | # 安装mysql服务 41 | mysqld -install 42 | # 初始化mysql服务 43 | mysqld --initialize-insecure --user=mysql 44 | # 启动mysql服务 45 | net start mysql 46 | # 登录mysql 47 | mysql -u root -p //此时系统无密码,可以直接回车 48 | # 修改初始密码 49 | mysqladmin -u root password //回车,然后设置密码并确认 50 | # 重新登录 51 | mysql -u root -p //输入设置的密码即可 52 | ``` 53 | 54 | -------------------------------------------------------------------------------- /notes/第3章 MySQL数据库/3.3.1_MySQL基础知识_1.md: -------------------------------------------------------------------------------- 1 | ## MySQL基础知识 2 | 3 | ### 数值类型 4 | 5 | MySQL支出所有标准SQL数值数据类型。这些数值类型包括严格数值数据类型(integer,smallint,decimal和numeric),以及近似数值数据类型(float,real,和double precision)。关键字int和integer的同义词,关键字dec是decimal的同义词。 6 | 7 | 作为SQL标准的扩张,MySQL也支出整数类型tinyint、meiumint和bigint。 8 | 9 | | 数据类型 | 含义 | 10 | | ------------ | ------------------------------------- | 11 | | tinyint(m) | 1个字节,范围为-128~127 | 12 | | smallint(m) | 2个字节,范围为-32768~32767 | 13 | | mediumint(m) | 3个字节,范围为-8388608~8388607 | 14 | | int(m) | 4个字节,范围为-2147483648~2147483647 | 15 | | big(int) | 8个字节,范围为 | 16 | 17 | $$ 18 | -9.22*10^{18} , 9.22*10^{18} 19 | $$ 20 | 21 | 22 | 23 | #### 浮点类型 24 | 25 | | 数据类型 | 含义 | 26 | | -------------- | ------------------------------------------------------------ | 27 | | float(m,d) | 单精度浮点类型,4字节,m是十进制数字的总格式,d是小数点后面的数字个数 | 28 | | double(m,d) | 双精度浮点型,8字节 | 29 | | decimal(m,d) | 定点类型在数据库中存放的是精确值。m是最大个数,d是小数点右侧数字的个数 | 30 | 31 | #### 字符串类型 32 | 33 | | 数据类型 | 含义 | 34 | | ---------- | ---------------- | 35 | | char(n) | 固定长度字符串 | 36 | | varchar(n) | 可变长度字符串 | 37 | | tinytext | 短文本字符串 | 38 | | text | 长文本数据 | 39 | | mediumtext | 中等长度文本数据 | 40 | | longtext | 极大文本数据 | 41 | 42 | #### 日期和时间类型 43 | 44 | | 类型 | 格式 | 45 | | --------- | ------------------- | 46 | | date | YYYY-MM-DD | 47 | | time | HH:MM:SS | 48 | | year | YYYY | 49 | | datetime | YYYY-MM-DD HH:MM:SS | 50 | | timestamp | YYYY-MM-DD HH:MM:SS | 51 | 52 | #### 复合类型 53 | 54 | | 类型 | 格式 | 55 | | ---- | ----------------- | 56 | | set | set("m1","m2"...) | 57 | | enum | enum("m1","m2"..) | 58 | 59 | 60 | 61 | ### 数据库操作 62 | 63 | #### 启动数据库 64 | 65 | `mysql -uroot -p` 回车后再输入密码 66 | 67 | #### 创建数据库 68 | 69 | ```mysql 70 | show databases #查看所有的数据库 71 | create datebase mytestdb; 72 | ``` 73 | 74 | #### 创建表 75 | 76 | ```mysql 77 | show tables; #查看所有表 78 | desc 数据表名字; #查看数据表结构 79 | use mytestdb; 80 | create table `user`( 81 | `id` int(10) not null primary key auto_crement, 82 | `name` varchar(50) not null, 83 | age int, 84 | income); 85 | ``` 86 | 87 | ```mysql 88 | -- 根据已有的表创建新表 89 | -- 只包含结构 90 | create table tab_new like tab_old; 91 | -- 包含结构和数据 92 | create table tab_new as select * from tab_old; 93 | ``` 94 | 95 | #### 增删改查操作 96 | 97 | ```mysql 98 | -- 添加 99 | inser into user(name, age, income) values('jack', 25, 5000); 100 | -- 查询 101 | select * from user; 102 | -- 修改 103 | update user set income = 9000 where id = 1; 104 | -- 删除 105 | delete from user where id = 2; 106 | ``` 107 | 108 | #### 对表结构的操作 109 | 110 | ```mysql 111 | alter table user address varchar(100); 112 | alter table user change address addr varchar(80); 113 | alter table user drop addr; 114 | alter table user rename users; 115 | ``` 116 | 117 | #### 删除数据库和表 118 | 119 | ```mysql 120 | drop table user; 121 | drop database mytestdb; 122 | ``` 123 | 124 | -------------------------------------------------------------------------------- /notes/第3章 MySQL数据库/3.4_Python操作MySQL.md: -------------------------------------------------------------------------------- 1 | ## Python操作MySQL 2 | 3 | ### 安装PyMySQL 4 | 5 | ```python 6 | pip install PyMySQL 7 | ``` 8 | 9 | ### 创建数据库 10 | 11 | ```mysql 12 | create database if not exists mytestdb character set utf8; 13 | use mytestdb; 14 | drop table if exists `employee`; 15 | create table `employee` ( 16 | `id` int(11) not null auto_increment, 17 | `name` varchar(40) default null, 18 | `age` int default null, 19 | `sex` char(1) default null, 20 | `income` float default null, 21 | primary key (`id`)) engine=InnoDB default charset=utf8; 22 | ``` 23 | 24 | ### 数据库插入操作 25 | 26 | ```python 27 | import pymysql 28 | # 打开数据库连接 29 | db = pymysql.connect(host="192.168.0.105", user="root", password="582153", 30 | database="mytestdb", port=3306) 31 | # 使用cursor()方法获取操作游标 32 | cursor = db.cursor() 33 | # SQL插入预计 34 | sql = "insert into employee(name, age, sex, income) values('%s', '%d', '%s', '%d')" % ('王五1', 25, 'F', 5000) 35 | try: 36 | # 执行sql语句 37 | cursor.execute(sql) 38 | # 提交到数据库执行 39 | db.commit() 40 | except Exception as e: 41 | print(e) 42 | db.rollback() 43 | finally: 44 | # 关闭数据库 45 | db.close() 46 | ``` 47 | 48 | 在数据库里插入单条数据时,使用的数据格式`'%s', '%d', '%s', '%d'` 49 | 50 | ### 数据库批量插入操作 51 | 52 | ```python 53 | import pymysql 54 | # 打开数据库连接 55 | db = pymysql.connect(host="192.168.0.105", user="root", password="582153", 56 | database="mytestdb", port=3306) 57 | # 使用cursor()方法获取操作游标 58 | cursor = db.cursor() 59 | # SQL插入预计 60 | sql = "insert into employee(name, age, sex, income) values(%s, %s, %s, %s)" 61 | ls = [] 62 | employee1 = ('张三', 22, 'F', 2000) 63 | employee2 = ('李四', 23, 'M', 3000) 64 | ls.append(employee1) 65 | ls.append(employee2) 66 | try: 67 | # 执行sql语句 68 | cursor.executemany(sql, ls) 69 | # 提交到数据库执行 70 | db.commit() 71 | except Exception as e: 72 | print(e) 73 | db.rollback() 74 | finally: 75 | # 关闭数据库 76 | db.close() 77 | ``` 78 | 79 | 在数据库里插入多条数据时,使用的数据格式`%s, %s, %s, %s` 80 | 81 | ### 数据库查询操作 82 | 83 | `fetchone/fetchall/fetchmany` 84 | 85 | ```python 86 | import pymysql 87 | # 打开数据库连接 88 | db = pymysql.connect(host="192.168.0.105", user="root", password="582153", 89 | database="mytestdb", port=3306) 90 | # 使用cursor()方法获取操作游标 91 | cursor = db.cursor() 92 | # SQL插入预计 93 | sql = "select * from employee where income > %d" % (2000) 94 | try: 95 | # 执行sql语句 96 | cursor.execute(sql) 97 | # 获取所有记录列表 98 | results = cursor.fetchall() 99 | for row in results: 100 | id = row[0] 101 | name = row[1] 102 | age = row[2] 103 | sex = row[3] 104 | income = row[4] 105 | # 打印结果 106 | print("id=%s, name=%s, age=%d, sex=%s, income=%d" % (id, name, age, sex, income)) 107 | except Exception as e: 108 | print(e) 109 | finally: 110 | # 关闭数据库 111 | db.close() 112 | ``` 113 | 114 | 数据库查询操作时,注意查询内容以元组形式`(id, name, age, sex, income)` 115 | 116 | ### 数据库更新操作 117 | 118 | ```python 119 | import pymysql 120 | # 打开数据库连接 121 | db = pymysql.connect(host="192.168.0.105", user="root", password="582153", 122 | database="mytestdb", port=3306) 123 | # 使用cursor()方法获取操作游标 124 | cursor = db.cursor() 125 | # SQL插入预计 126 | sql = "update employee set age='%d' where id = %s" % (28, 1) 127 | try: 128 | # 执行sql语句 129 | cursor.execute(sql) 130 | db.commit() 131 | except Exception as e: 132 | print(e) 133 | finally: 134 | # 关闭数据库 135 | db.close() 136 | ``` 137 | 138 | ### 数据库删除操作 139 | 140 | ```python 141 | import pymysql 142 | # 打开数据库连接 143 | db = pymysql.connect(host="192.168.0.105", user="root", password="582153", 144 | database="mytestdb", port=3306) 145 | # 使用cursor()方法获取操作游标 146 | cursor = db.cursor() 147 | # SQL插入预计 148 | sql = "delete from employee where id = '%s'" % (1) 149 | try: 150 | # 执行sql语句 151 | cursor.execute(sql) 152 | db.commit() 153 | except Exception as e: 154 | print(e) 155 | finally: 156 | # 关闭数据库 157 | db.close() 158 | ``` 159 | 160 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/1.爬虫基础/6.1.1_爬虫基础理论.md: -------------------------------------------------------------------------------- 1 | # 爬虫基础 2 | 3 | --- 4 | 5 | ## HTTP基本原理 6 | 7 | 在本节中,我们会详细了解HTTP的基本原理,了解在浏览器中敲入URL到获取网页内容之间发生了什么。了解了这些内容,有助于我们进一步了解爬虫的基本原理。 8 | 9 | ### URI和URL 10 | 11 | URI的全称为Uniform Resource Identifier,即统一资源标识符,URL的全称为Univeral Resource Locator,即统一资源定位符。URL是URI的子集。URI还包括一个子类叫做URN,它的全称为Universal Resource Name,即统一资源名称。URN只命名资源而不指定如何定位资源。但是目前的互联网中,URN用的很少,所有几乎所有的URI都是URL,一般的网页链接我们可以称为URL,也可以称为URI。 12 | 13 | ### 超文本 14 | 15 | 超文本,英文为hypertext,我们在浏览器里看到的网页就是抄完便捷性而成的,其页面源代码是一系列HTML代码,里面包含一系列标签。浏览器解析这些标签后,使形成了我们平常看到的网页,而网页的源代码HTML就可以称为超文本。 16 | 17 | ### HTTP和HTTPS 18 | 19 | HTTP的全称是Hyper Text Transfer Protocol,中文叫做超文本传输协议。HTTPS的全称为Hyper Text Transfer Protocol over Secure Socket Layer,是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,简称HTTPS。 20 | 21 | ### HTTP请求过程 22 | 23 | ![Request和Response](D:\repository\PythonNotes\images\Request和Response.png) 24 | 25 | ### 请求 26 | 27 | 请求,由客户端向服务端发出,可以分为4部分内容:请求方法,请求网址,请求头和请求体。 28 | 29 | #### 请求方法 30 | 31 | | 方法 | 描述 | 32 | | ------- | ------------------------------------------------ | 33 | | GET | 请求页面,并返回页面内容 | 34 | | HEAD | 返回请求头 | 35 | | POST | 用于提交表单或上传文件 | 36 | | PUT | 从客户端向服务器传送的数据取代指定文档中的内容 | 37 | | DELETE | 删除指定页面 | 38 | | CONNECT | 把服务器当做跳板,让服务器代替客户端访问其他网页 | 39 | | OPTIONS | 允许客户端查看服务器的性能 | 40 | | TRACE | 主要用于测试或诊断 | 41 | 42 | ### 响应 43 | 44 | #### 响应状态码 45 | 46 | #### 响应头 47 | 48 | #### 响应体 49 | 50 | ## 网页基础 51 | 52 | 用浏览器访问网站时,页面各不相同,我们需要了解网页的基本组成、结构和节点等内容。 53 | 54 | ### 网页的组成 55 | 56 | 网页可以分为三大部分——HTML、CSS和JavaScript。HTML(Hyper Text Markup Language)形成网页的架构,CSS(Cascading Style Sheets)使页面变得更为美观,JavaScript是用户与信息之间不只是一种浏览与显示关系,而是实现了一种实时、动态、交互的页面功能。 57 | 58 | ### 网页的结构 59 | 60 | ```html 61 | 62 | 63 | 64 | 65 | This is a Demo 66 | 67 | 68 |
69 |
70 |

Hello World

71 |

Hello, this is a paragraph.

72 |
73 |
74 | 75 | 76 | ``` 77 | 78 | ### 节点树及节点间的关系 79 | 80 | 在HTML中,所有标签定义的内容都是节点,他们构成了一个HTML DOM树。 81 | 82 | ![节点树及节点间的关系](D:\repository\PythonNotes\images\节点树及节点间的关系.png) 83 | 84 | ### CSS选择器用法 85 | 86 | ## 爬虫基本原理 87 | 88 | 我们可以把互联网比作一张大网,而爬虫便是在网上爬行的蜘蛛。把网的节点比作一个个网页,爬虫爬到这就相当于访问了该页面,获取了信息。可以把节点间的连线比作网页与网页之间的链接关系,这样蜘蛛通过一个节点后,可以顺着节点连线继续爬行到下一个节点,即通过一个网页继续获取后续的页面,这样整个网的节点便可以被蜘蛛全部爬行到,网站的数据就可以被抓去下来。 89 | 90 | ### 爬虫基本流程 91 | 92 | #### 获取页面 93 | 94 | #### 提取信息 95 | 96 | #### 保存数据 97 | 98 | #### 自动化程序 99 | 100 | ### 能抓怎样的数据 101 | 102 | 字符串,图片,视频和音频。 103 | 104 | ### JavaScript渲染页面 105 | 106 | 有时候,我们在用urllib或requests抓取页面时,得到的源代码实际和浏览器看到的不一样。这是一个非常常见的问题。现在越来越多的采用Ajax、前端模块化工具来构建,整个网络可能都是有JavaScript渲染出来的,因此,对于这样的情况,我们可以分析其后台Ajax接口,也可使用Selenium、Splash这样的库来实现模拟JavaScript渲染。 107 | 108 | ## 会话和Cookies 109 | 110 | ## 代理的基本原理 111 | 112 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/1.爬虫基础/6.1.2_爬虫常用库的安装.md: -------------------------------------------------------------------------------- 1 | # 爬虫常用库的安装 2 | 3 | --- 4 | 5 | ## 请求库的安装 6 | 7 | 爬虫可以简单分为几步:抓取页面、分析页面、获取数据和存储数据。在抓取页面的过程中,我们需要模拟浏览器向服务器发出请求,所以需要用到一些Python可来实现HTTP请求操作。以下库的安装尽量保持在使用vpn的情况下安装,不然可能会因为网络的问题无法安装成功。 8 | 9 | ### requests安装 10 | 11 | `pip install requests` 12 | 13 | ### Selenium安装 14 | 15 | Selenium是一个自动化测试工具,利用它我们可以驱动浏览器执行特定的动作,如点击、下拉等操作。对于一些JavaScript渲染的页面来说,这种抓取方式非常有效。 16 | 17 | `pip install selenium` 18 | 19 | ### ChromeDriver安装 20 | 21 | Selenium库的使用需要浏览器配合,我们使用chrome浏览器。下载完成后,把chromedriver.exe复制到anaconda对于python的Scripts目录下。 22 | 23 | ### PhantomJS安装 24 | 25 | PhantomJS是一个无界面的、可脚本编程的Webkit浏览器引擎,它原生支持多种Web标准:DOM操作,CSS选择器,JSON,Canvas和SVG等。Selenium支持PhantomJS,这样在运行的时候就不会弹出一个浏览器。直接进入网站下载,再配置环境。 26 | 27 | ### aiohttp安装 28 | 29 | 之前介绍的requests库是一个阻塞式HTTP请求库,当我们发出一个请求后,程序会一直等待服务器响应,直到得到响应后,程序才会进行下一步处理。其实,这个过程比较耗费时间。如果程序可以在这个等待过程中做一些其他的事情,如进行请求的调度、响应的处理等,那么爬取效率一定会大大提高。 30 | 31 | aiohttp就是这样一个提供异步Web服务的库,Python中加入async/await关键字,是的毁掉的写法更加直观和人性化。aiohttp的异步操作借助于async/await关键字的写法变得更加简洁,架构更加清晰,使用异步请求库进行数据抓取时,大大提高效率。 32 | 33 | `pip install aiohttp` 34 | 35 | `pip install cchardet aiodns` 36 | 37 | ## 解析库的安装 38 | 39 | 抓取网页代码后,下一步就是从网页中提取信息。提取信息的方式众多,可以使用正则,也可以使用各种库。 40 | 41 | ### lxml安装 42 | 43 | lxml是Python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且效率高。 44 | 45 | `pip install lxml` 46 | 47 | ### Beautiful Soup安装 48 | 49 | `pip install beautifulsoup4` 50 | 51 | ### pyquery安装 52 | 53 | pyquery通用是一个强大的网页解析工具,它提供了和jQuery类似的语法来解析HTML文档,支持CSS选择器,使用方便。 54 | 55 | `pip install pyquery` 56 | 57 | ### tesserocr安装 58 | 59 | ORC,即Optical Character Recognition,光学字符识别,是指通过扫描字符,然后通过其形状将其翻译成电子文本的过程。对于图形验证码来说,他们都是一些不规则字符,这些字符确实是由字符稍加扭曲变换得到的内容。 60 | 61 | `conda install -c simonflueckiger tesserocr` 62 | 63 | ## 数据库的安装 64 | 65 | 作为数据存储的重要部分,数据库通用是必不可少的,数据库可以分为关系型数据库和非关系型数据库。关系型数据库如SQLite、MySql、Oracle等,其数据库是以表的形式存储;非关系型数据库如MongoDB、Redis等,它们的存储形式是键值对,存储形式更加灵活。 66 | 67 | 具体安装见第四章。 68 | 69 | ## 使用Python操作数据库的库 70 | 71 | ### PyMySQL安装 72 | 73 | `pip install pymysql` 74 | 75 | ### PyMongo安装 76 | 77 | `pip install pymongo` 78 | 79 | ### redis-py安装 80 | 81 | `pip install redis` 82 | 83 | ### RedisDump安装 84 | 85 | 1. 安装Ruby 86 | 2. `gem install redis-dump` 87 | 88 | ## Web库安装 89 | 90 | ### Flask安装 91 | 92 | `pip install flask` 93 | 94 | ### Tornado安装 95 | 96 | `pip install tornado` 97 | 98 | ## App爬取相关库的安装 99 | 100 | 跳过。。。。。。 101 | 102 | ## 爬虫框架的安装 103 | 104 | ### pyspider安装 105 | 106 | `pip install pyspider -i http://pypi.souban.com/simple/ --trusted-host pypi.douban.com` 107 | 108 | ### Scrapy安装 109 | 110 | `conda install Scrapy` 111 | 112 | ### scrapy-splash安装----涉及部署库 113 | 114 | 没安装好。。 115 | 116 | ### Scrapy-Redis安装 117 | 118 | `pip install scrapy-redis` 119 | 120 | ## 部署相关库的安装--------有问题没完成 121 | 122 | ### Docker安装 123 | 124 | ### Scrapyd安装 125 | 126 | ### Scrapyd-client安装 127 | 128 | ### Scrapy API安装 129 | 130 | ### Scrapyrt安装 131 | 132 | ### Gerapy安装 133 | 134 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/2.获取网页源代码/6.2.1_curl详解.md: -------------------------------------------------------------------------------- 1 | # curl详解 2 | 3 | --- 4 | 5 | ## 下载 6 | 7 | 链接:https://bintray.com/vszakats/generic/curl/ 8 | 9 | 下载后解压,再配置环境 10 | 11 | ## 用法讲解 12 | 13 | | 参数 | 说明 | 实例 | 14 | | ---- | --------------------------------- | ------------------------------------- | 15 | | -A | 设置user-agent | curl -A 'Chrome' http://www.baidu.com | 16 | | -X | 指定请求方式 | curl -X POST http://www.baidu.com | 17 | | -I | 返回请求头信息 | | 18 | | -d | 以post方法请求url,并发送相应参数 | | 19 | | | 下载文件并以远程的文件名保存 | | 20 | | | 可以自己命名保存文件 | | 21 | | -L | 跟随重定向请求 | | 22 | | -H | 设置头信息 | | 23 | | -k | 运行发起不安全的SSL请求 | | 24 | | -b | 设置cookies | | 25 | | | 不显示其他无关信息 | | 26 | 27 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/2.获取网页源代码/6.2.2_Urllib库详解.md: -------------------------------------------------------------------------------- 1 | # Urllib库详解 2 | 3 | --- 4 | 5 | 学习爬虫,最初的操作便是把浏览器向服务器发出请求,用urllib库,不用深入深入到底层去了解它到底是怎样传输和通信。 6 | 7 | ## urllib模块 8 | 9 | | 模块 | 功能 | 10 | | ------------------ | ------------------ | 11 | | urllib.request | 请求模块 | 12 | | urllib.error | 异常处理模块 | 13 | | urllib.parse | url解析模块 | 14 | | urllib.robotparser | robots.txt解析模块 | 15 | 16 | ## 发送请求 17 | 18 | 使用urllib的request模块,我们可以方便的实现请求的发送并得到响应。 19 | 20 | ### urlopen 21 | 22 | urllib.request模块提供了基本的构造HTTP请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时它还带有处理授权验证码,重定向,浏览器cookies和其他内容。 23 | 24 | ```python 25 | import urllib.request 26 | import urllib.parse 27 | 28 | # 发起请求 29 | response = urllib.request.urlopen('http://httpbin.org') 30 | print(response.read().decode('utf8')) 31 | print(type(response)) 32 | 33 | # 获得属性 34 | print(response.status) 35 | print(response.getheaders()) 36 | print(response.getheader('Server')) 37 | 38 | # data参数 39 | data = bytes(urllib.parse.urlencode({'word':'hello'}), encoding='utf-8') 40 | response = urllib.request.urlopen('http://httpbin.org/post', data=data) 41 | print(response.read()) 42 | 43 | # timeout参数 44 | response = urllib.request.urlopen('http://httpbin.org/get', timeout=1) 45 | print(response.read()) 46 | ``` 47 | 48 | ### Request 49 | 50 | ```python 51 | # 综合用法 52 | from urllib import request, parse 53 | 54 | url = 'http://httpbin.org/post' 55 | headers = { 56 | 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36', 57 | 'Host':'httpbin.org' 58 | } 59 | dic = { 60 | 'name':'Gemey' 61 | } 62 | data = bytes(parse.urlencode(dic), encoding='utf8') 63 | req = request.Request(url=url, data=data, headers=headers, method='POST') 64 | response = request.urlopen(req) 65 | print(response.read().decode('utf8')) 66 | ``` 67 | 68 | ### 高级用法 69 | 70 | ```python 71 | # 1.验证用户名和密码 72 | from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener 73 | from urllib.error import URLError 74 | 75 | username = 'username' 76 | password = 'password' 77 | url = 'http://localhost:5000/' 78 | 79 | p = HTTPPasswordMgrWithDefaultRealm() 80 | p.add_password(None, url, username, password) 81 | auth_handler = HTTPBasicAuthHandler(p) 82 | openner = build_opener(auth_handler) 83 | try: 84 | result = openner.open(url) 85 | html = result.read().decode('utf-8') 86 | print(html) 87 | except URLError as e: 88 | print(e.reason) 89 | ``` 90 | 91 | ```python 92 | # 2.添加代理,代理实时更新,不能一直使用 93 | import urllib.request 94 | 95 | proxy_handler = urllib.request.ProxyHandler({ 96 | 'http':'http://127.0.0.1:9743', 97 | 'https':'https://127.0.0.1:9743' 98 | }) 99 | opener = urllib.request.build_opener(proxy_handler) 100 | response = opener.open('http://www.baidu.com') 101 | print(response.read()) 102 | ``` 103 | 104 | ```python 105 | # 3.cookies 106 | import http.cookiejar 107 | import urllib.request 108 | 109 | cookie = http.cookiejar.CookieJar() 110 | handler = urllib.request.HTTPCookieProcessor(cookie) 111 | opener = urllib.request.build_opener(handler) 112 | response = opener.open('http://www.baidu.com') 113 | for item in cookie: 114 | print(item.name+'='+item.value) 115 | ``` 116 | 117 | ## 异常处理 118 | 119 | ```python 120 | # 异常处理 121 | from urllib import request, error 122 | 123 | try: 124 | response = request.urlopen('http://cuiqingcai.com/index.htm') 125 | except error.URLError as e: 126 | print(e.reason) 127 | ``` 128 | 129 | ## 解析链接 130 | 131 | ```python 132 | # urlparse解析 133 | from urllib.parse import urlparse 134 | 135 | result = urlparse('http://www.baidu.com/index.html;user?id=5#comment') 136 | print(type(result), result) 137 | ``` 138 | 139 | ```python 140 | # urlunparse进行拼接 141 | from urllib.parse import urlunparse 142 | 143 | data = ['http','www.baidu.com','index.html','user','a=6','comment'] 144 | print(urlunparse(data)) 145 | ``` 146 | 147 | ```python 148 | # urljoin 149 | from urllib.parse import urljoin 150 | print(urljoin('http://www.baidu.com','https://cuiqingcai.com/FAQ.html')) 151 | ``` 152 | 153 | ```python 154 | # urlencode 155 | from urllib.parse import urlencode 156 | 157 | params = { 158 | 'name':'gemey', 159 | 'age':22 160 | } 161 | base_url = 'http://www.baidu.com?' 162 | url = base_url + urlencode(params) 163 | print(url) 164 | ``` 165 | 166 | ## 分析Robots协议 167 | 168 | Robots协议也称为爬虫协议,机器人协议,它的全名叫做爬虫排除标准,用来告诉爬虫和所有引擎哪些页面可以抓取,哪些不可以抓取。它通常是一个叫做robots.txt的文本文件,一般放在网站的根目录下。当搜索爬虫访问一个站点时,首先会检查这个站点检查这个根目录是否存在协议文件。useragent规定哪些爬虫不能爬,Disallow规定不允许抓取的目录。 -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/2.获取网页源代码/6.2.3_Requests库详解.md: -------------------------------------------------------------------------------- 1 | # Requests库详解 2 | 3 | --- 4 | 5 | Requests是用Python语言编写,基于urllib,采用Apache2 Licensed开源协议的HTTP库。它比urllib更加方便,可以节约我们大量的工作,满足HTTP测试需求。 6 | 7 | ## 基本用法 8 | 9 | ```python 10 | # requests库爬虫标准 11 | import requests 12 | 13 | url = 'http://www.baidu.com' 14 | headers = { 15 | 'User-Agent':'Mozilla/5.0' 16 | } 17 | try: 18 | response = requests.get(url, headers = headers) 19 | response.raise_for_status() 20 | response.encoding = r.apparent_encoding 21 | return response.text 22 | except: 23 | print('爬取失败') 24 | ``` 25 | 26 | ```python 27 | # 实例引入 28 | import requests 29 | 30 | response = requests.get('https://www.baidu.com/') 31 | print(type(response)) 32 | print(response.status_code) 33 | print(type(response.text)) 34 | print(response.text) 35 | print(response.cookies) 36 | ``` 37 | 38 | ```python 39 | # 各种请求方式 40 | import requests 41 | 42 | requests.post('http://httpbin.org/post') 43 | requests.put('http://httpbin.org/put') 44 | requests.delete('http://httpbin.org/delete') 45 | requests.head('http://httpbin.org/get') 46 | requests.options('http://httpbin.org/get') 47 | ``` 48 | 49 | ```python 50 | # 带参数的get请求 51 | import requests 52 | 53 | data = { 54 | 'name':'gemey', 55 | 'age':22 56 | } 57 | response = requests.get('http://httpbin.org/get', params=data) 58 | print(response.text) 59 | ``` 60 | 61 | ```python 62 | # 转换成json格式 63 | import requests 64 | import json 65 | 66 | response = requests.get('https://httpbin.org/get') 67 | print(type(response.text)) 68 | print(response.json()) 69 | print(json.loads(response.text)) 70 | print(type(response.json())) 71 | ``` 72 | 73 | ```python 74 | # 获取二进制数据 75 | import requests 76 | 77 | response = requests.get('http://github.com/favicon.ico') 78 | with open('favicon.ico','wb') as f: 79 | f.write(response.content) 80 | f.close() 81 | ``` 82 | 83 | ```python 84 | # 添加headers 85 | import requests 86 | 87 | headers = { 88 | 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36' 89 | } 90 | response = requests.get('https://www.zhihu.com/explore', headers=headers) 91 | print(response.text) 92 | ``` 93 | 94 | ## 高级用法 95 | 96 | ```python 97 | # 文件上传 98 | import requests 99 | 100 | files = {'file':open('favicon.ico', 'rb')} 101 | response = requests.post('http://httpbin.org/post', files=files) 102 | print(response.text) 103 | ``` 104 | 105 | ```python 106 | # 获取cookies 107 | import requests 108 | 109 | response = requests.get('http://www.baidu.com') 110 | print(response.cookies) 111 | for key, value in response.cookies.items(): 112 | print(key + '=' + value) 113 | ``` 114 | 115 | ```python 116 | # 会话维持 117 | import requests 118 | 119 | s = requests.Session() 120 | s.get('http://httpbin.org/cookies/set/number/123456789') 121 | response = s.get('http://httpbin.org/cookies') 122 | print(response.text) 123 | ``` 124 | 125 | ```python 126 | # 证书验证 127 | import requests 128 | # 去掉警告提示 129 | from requests.packages import urllib3 130 | urllib3.disable_warnings() 131 | 132 | response = requests.get('https://www.12306.cn', verify=False) 133 | print(response.status_code) 134 | ``` 135 | 136 | ```python 137 | # 异常处理 138 | import requests 139 | 140 | try: 141 | response = requests.get('http://httpbin.org/get', timeout=0.1) 142 | print(response.status_code) 143 | except Exception as e: 144 | print(e) 145 | ``` 146 | 147 | ```python 148 | # 图片下载保存路径和命名方法 149 | import requests 150 | import os 151 | 152 | 153 | url = 'https://img10.360buyimg.com/n5/s75x75_jfs/t1/42272/20/10323/135815/5d3d6adfE63e2cb03/7c966e6a71f02044.jpg' 154 | headers = { 155 | 'User-Agent':'Mozilla/5.0' 156 | } 157 | root = 'D://images//' 158 | path = root + url.split('/')[-1] 159 | try: 160 | if not os.path.exists(root): 161 | os.mkdir(root) 162 | if not os.path.exists(path): 163 | response = requests.get(url, headers=headers) 164 | response.raise_for_status() 165 | response.encoding = response.apparent_encoding 166 | with open(path, 'wb') as f: 167 | f.write(response.content) 168 | f.close() 169 | print('文件下载完成') 170 | else: 171 | print('文件已存在') 172 | except: 173 | print('爬取失败') 174 | ``` 175 | 176 | ## 打印出现中文乱码 177 | 178 | ```python 179 | # 以网页编码格式解析 180 | response.encoding = response.apparrent_code 181 | # 先返回二进制格式,再转码成utf-8 182 | response.content.decode('utf-8') 183 | ``` 184 | 185 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/3.解析网页数据/6.3.1_正则表达式.md: -------------------------------------------------------------------------------- 1 | # 正则表达式 2 | 3 | --- 4 | 5 | 见第四章模块部分 -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/3.解析网页数据/6.3.2_XPath库详解.md: -------------------------------------------------------------------------------- 1 | # XPath库详解 2 | 3 | --- 4 | 5 | 上一节中,我们实现了一个最基本的爬虫,但是提取页面信息时使用的是正则表达式,这还是比较繁琐,而且万一有地方写错了,可能导致匹配失败。对于网友的节点来说,他可以定义id、class或其他属性。而且节点之间还有层次关系,在网页中可以通过XPath或CSS选择器来定位一个或多个节点。用选择器提取节点,然后在调用相应的方法获取正文内容或说下,会更加方便。 6 | 7 | XPath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言。其功能强大,提供了非常简洁明了的路径选择表达式。XPath筛选后的结果返回为列表。 8 | 9 | ## 常用规则 10 | 11 | | 表达式 | 描述 | 12 | | -------- | ------------------------ | 13 | | nodename | 此节点的所有子节点 | 14 | | / | 从当前节点选取直接子节点 | 15 | | // | 从当前节点选取子孙节点 | 16 | | . | 选取当前节点 | 17 | | .. | 选取当前节点的父节点 | 18 | | @ | 选取属性 | 19 | 20 | ## 基本使用方法 21 | 22 | ```python 23 | from lxml import etree 24 | 25 | # 把html文件保存到本地,命名test 26 | text = """ 27 |
28 | 35 |
36 | """ 37 | 38 | # 基本使用 39 | html = etree.parse('./test.html', etree.HTMLParser()) 40 | # 所有节点 41 | result = html.xpath('//*') 42 | # 子节点 43 | result = html.xpath('//li/a') 44 | # 父节点 45 | result = html.xpath('//a[@href="link4.html"]/parent::*/@class') 46 | # 属性匹配 47 | result = html.xpath('//li[@class="item-0"]') 48 | # 文本获取 49 | result = html.xpath('//li[@class="item-0"]/a/text()') 50 | # 属性获取 51 | result = html.xpath('//li/a/@href) 52 | # 属性多值匹配 53 | result = html.xpath('//li[contains(@class, "li")]/a/text()') 54 | # 多属性匹配 55 | result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()') 56 | # 按序选择 57 | result = html.xpath('//li[last()]/a/text()') 58 | # 节点轴选择 59 | result = html.xpath('//li[1]/ancestor::*') 60 | # 拼接同级标签内容 61 | total = html.xpath('concat(//span[@class="total"]/span/text(),//span[@class="unit"]/span/text())') 62 | ``` 63 | 64 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/3.解析网页数据/6.3.3_BeautifulSoup库详解.md: -------------------------------------------------------------------------------- 1 | # BeautifulSoup库详解 2 | 3 | --- 4 | 5 | 灵活有方便的网页解析库,处理高效,支持多种解析器。利用它不用编写正则表达式即可方便地实现网页信息的提取。 6 | 7 | ## 解析库 8 | 9 | Python标准库,lxml HTML解析库,html5lib 10 | 11 | ## 基本用法 12 | 13 | ```python 14 | html = """ 15 | The Dormouse's story 16 | 17 |

The Dormouse's story

18 |

Once upon a time there were three little sisters; and their names were 19 | , 20 | Lacie and 21 | Tillie; 22 | and they lived at the bottom of a well.

23 |

...

24 | """ 25 | from bs4 import BeautifulSoup 26 | soup = BeautifulSoup(html, 'lxml') 27 | 28 | print(soup.prettify()) 29 | print(soup.title.string) 30 | ``` 31 | 32 | ## 节点选择器 33 | 34 | ```python 35 | html = """ 36 | The Dormouse's story 37 | 38 |

The Dormouse's story

39 |

Once upon a time there were three little sisters; and their names were 40 | , 41 | Lacie and 42 | Tillie; 43 | and they lived at the bottom of a well.

44 |

...

45 | """ 46 | from bs4 import BeautifulSoup 47 | soup = BeautifulSoup(html, 'lxml') 48 | 49 | # 选择元素 50 | print(soup.title) 51 | print(soup.title.string) 52 | print(soup.head) 53 | print(soup.p) 54 | # 获取名称 55 | print(soup.title.name) 56 | # 获取属性 57 | print(soup.p.attrs) 58 | # 获取内容 59 | print(soup.p.string) 60 | # 嵌套选择 61 | print(soup.head.title.string) 62 | # 子节点 63 | print(soup.p.contents) # 列表形式 64 | print(soup.p.children) # 迭代器 65 | for i,child in enumerate(soup.p.children): 66 | print(i,child) 67 | # 子孙节点 68 | print(soup.p.descendants) # 迭代器 69 | for i,child in enumerate(soup.p.descendants): 70 | print(i,child) 71 | # 父节点 72 | print(soup.a.parent) 73 | # 祖先节点 74 | print(list(enumerate(soup.a.parents))) 75 | # 兄弟节点 76 | print(list(enumerate(soup.a.next_siblings))) 77 | print(list(enumerate(soup.a.previous_siblings))) 78 | ``` 79 | 80 | ## 方法选择器 81 | 82 | ```python 83 | html = """ 84 | .... 85 | """ 86 | from bs4 import BeautifulSoup 87 | soup = BeautifulSoup(html, 'lxml') 88 | 89 | # find_all 90 | ## name 91 | print(soup.find_all(name = 'ul')) 92 | # 层层迭代查找 93 | for ul in soup.find_all('ul'): 94 | print(ul.find_all('li')) 95 | # 查找属性 96 | print(soup.find_all(attrs={'name':'elements'})) 97 | print(soup.find_all(class_='elements')) 98 | # 文本内容 99 | print(soup.find_all(text='Foo')) 100 | ``` 101 | 102 | find_all返回所有元素,find返回单个元素。 103 | 104 | ## CSS选择器 105 | 106 | ```python 107 | html = "...." 108 | from bs4 import BeautifulSoup 109 | soup = BeautifulSoup(html, 'lxml') 110 | 111 | print(soup.select('.panel .panel-heading')) 112 | print(soup.select('ul li')) 113 | print(soup.select('#list-2 .element')) 114 | # 获取属性 115 | for ul in soup.select('ul'): 116 | print(ul['id']) 117 | # 获取内容 118 | for li in soup.select('li'): 119 | print(li.get_text()) 120 | ``` 121 | 122 | ## 总结 123 | 124 | 1. 推荐使用lxml解析库,必要时使用html.parser 125 | 126 | 2. 标签选择率先功能弱但速度快 127 | 128 | 3. 建议使用find(),find_all()长匹配单个或多个结果 129 | 130 | 4. 如果对CSS选择器熟悉建议使用select() 131 | 132 | 5. 记住常用的获取属性和文本值得方法 133 | 134 | 135 | 136 | ## MOOC课程 137 | 138 | ```python 139 | # BeautifulSoup库使用 140 | import requests 141 | from bs4 import BeautifulSoup 142 | 143 | url = 'http://www.baidu.com' 144 | response = requests.get(url) 145 | response.encoding = response.apparent_encoding 146 | response = response.text 147 | soup = BeautifulSoup(response, 'html.parser') 148 | print(soup.prettify()) 149 | ``` 150 | 151 | ### HTML基本格式![html基本格式](D:\repository\PythonNotes\images\html基本格式.png) 152 | 153 | 标签树:contents children descendents parent parents 154 | 155 | 平行标签树: 156 | 157 | ![标签树的平行遍历](D:\repository\PythonNotes\images\标签树的平行遍历.png) 158 | 159 | ### 总结 160 | 161 | ![BeautifullSoup总结1](D:\repository\PythonNotes\images\BeautifullSoup总结1.png) 162 | 163 | ![BeautifullSoup总结](D:\repository\PythonNotes\images\BeautifullSoup总结.png) -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/3.解析网页数据/6.3.4_PyQuery库详解.md: -------------------------------------------------------------------------------- 1 | # PyQuery库详解 2 | 3 | --- 4 | 5 | 强大又灵活的网页解析库。如果你觉得写正则起来太麻烦,你觉得BeautifulSoup语法太难进,如果你熟悉jQuery的语法,那么PyQuery就是你的最佳选择。 6 | 7 | ## 初始化 8 | 9 | ```python 10 | # 字符串初始化 11 | html = """ 12 |
13 | 20 |
21 | """ 22 | from pyquery import PyQuery as pq 23 | 24 | doc = pq(html) 25 | print(doc('li')) 26 | 27 | # URL初始化 28 | doc = py(url='http://www.baidu.com') 29 | print(doc('head')) 30 | 31 | # 文件初始化 32 | doc = pq(filename='demo.html') 33 | print(doc('li')) 34 | ``` 35 | 36 | ## 基本CSS选择器 37 | 38 | ```python 39 | html = """ 40 |
41 | 48 |
49 | """ 50 | from pyquery import PyQuery as pq 51 | doc = pq(html) 52 | 53 | print(doc('#container .list li')) 54 | ``` 55 | 56 | ## 查找元素 57 | 58 | ```python 59 | html = """ 60 |
61 | 68 |
69 | """ 70 | from pyquery import PyQuery as pq 71 | doc = pq(html) 72 | 73 | # 子节点 74 | items = doc('.list') 75 | print(items) 76 | lis = items.find('li') 77 | print(lis) 78 | # 父节点 79 | container = items.parent() 80 | print(container) 81 | # 祖先节点 82 | parents = items.parents() 83 | print(parents) 84 | # 兄弟节点 85 | li = doc('.list .item-0.active') # 并列 86 | print(li.siblings()) 87 | ``` 88 | 89 | ## 遍历 90 | 91 | ```python 92 | html = """ 93 |
94 | 101 |
102 | """ 103 | from pyquery import PyQuery as pq 104 | doc = pq(html) 105 | 106 | # 单个元素 107 | li = doc('.item-0.active') 108 | # 多个元素 109 | lis = doc('li').items() 110 | for li in lis: 111 | print(li) 112 | ``` 113 | 114 | ### 获取信息 115 | 116 | ```python 117 | html = """ 118 |
119 | 126 |
127 | """ 128 | from pyquery import PyQuery as pq 129 | doc = pq(html) 130 | 131 | # 获取属性 132 | a = doc('.item-0.active a') 133 | print(a) 134 | print(a.attr.href) 135 | # 获取文本 136 | print(a.text()) 137 | # 获取HTML 138 | print(a.html()) 139 | ``` 140 | 141 | ### DOM操作 142 | 143 | ```python 144 | html = """ 145 |
146 | 153 |
154 | """ 155 | from pyquery import PyQuery as pq 156 | doc = pq(html) 157 | 158 | li = doc('.item-0.active') 159 | print(li) 160 | li.removeClass('active') 161 | print(li) 162 | li.addClass('active') 163 | print(li) 164 | # attr、css 165 | li.attr('name','link') 166 | print(li) 167 | li.css('font-size','14px') 168 | print(li) 169 | # remove 170 | wrap = doc('.wrap') 171 | print(wrap.text()) 172 | wrap.find('p').remove() 173 | print(wrap.text()) 174 | ``` 175 | 176 | ### 伪类选择器 177 | 178 | ```python 179 | html = """ 180 |
181 | 188 |
189 | """ 190 | from pyquery import PyQuery as pq 191 | doc = pq(html) 192 | 193 | li = doc('li:first-child') 194 | print(li) 195 | ``` 196 | 197 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/3.解析网页数据/6.3.6_Splash的使用.md: -------------------------------------------------------------------------------- 1 | # Splash的使用 2 | 3 | --- 4 | 5 | Splash是一个JavaScript渲染服务,是一个带有HTTP API的轻量级浏览器,同时它对接了Python中的Twisted和QT库。利用它,我们同样可以实现动态渲染页面的抓取。 6 | 7 | ## 功能介绍 8 | 9 | 1. 异步方式处理多个页面渲染过程 10 | 2. 获取渲染后的页面的源代码或截图 11 | 3. 通过关闭图片渲染或者使用Adhlock规则来加快页面渲染速度 12 | 4. 可执行特定的JavaScript脚本 13 | 5. 可通过Lua脚本来控制页面渲染过程 14 | 6. 获取渲染的详细过程并通过HAR(HTTP Archive)格式呈现 15 | 16 | ## 实例引入 17 | 18 | 首先安装docker,由于docker会要求电脑的版本,所以可以安装docker Toolbox。然后在Docker Toolbox里面安装splash。 19 | 20 | `docker pull scrapinghub/splash`拉取镜像 21 | 22 | `docker run -p 8050:8050 scrapinghub/splash`运行 23 | 24 | 然后在网页中打开网址:192.168.99.100:8050 25 | 26 | ## Splash Lua脚本 27 | 28 | ```lua 29 | function main(splash, args) --main()名称时固定的 30 | splash:go('http://www.baidu.com') --获取页面 31 | splash:wait(0.5) --设置等待时间 32 | local title = splash:evaljs('document.title') 33 | return {title=title} 34 | end 35 | ``` 36 | 37 | ## Splash对象属性 38 | 39 | 前面例子中`main()`方法的第一个参数是splash,这个对象非常重要,它类似于Selenium中的WebDriver对象,我们可以调用它的一些属性和方法来控制加载过程。 40 | 41 | ### args 42 | 43 | 该属性可以获取加载是配置的参数,比如URL,如果为GET请求,它还可以获取GET请求参数;如果为POST请求,它可以获取表单提交的数据。Splash也指出使用第二个参数直接作为args。 44 | 45 | ```lua 46 | function main(splash, args) 47 | local url = args.url 48 | end 49 | ``` 50 | 51 | ### js_enabled 52 | 53 | 这个属性是Splash的JavaScript执行开关,可以将其配置为true或false来控制是否执行JavaScript代码,默认为true。 54 | 55 | ```lua 56 | function main(splash, args) 57 | splash:go('http://www.baidu.com') 58 | splash:wait(0.5) 59 | splash.js_enabled = false 60 | local title = splash:evaljs('document.title') 61 | return {title=title} 62 | end 63 | ``` 64 | 65 | ### resource_timeout 66 | 67 | 此属性可以设置加载的超时时间,单位是秒。如果设置为0或nil,表示不检测超时。 68 | 69 | ```lua 70 | function main(splash, args) 71 | splash.resource_timeout = 0.1 72 | splash:go('http://www.baidu.com') 73 | splash:wait(0.5) 74 | splash.js_enabled = false 75 | local title = splash:evaljs('document.title') 76 | return {title=title} 77 | end 78 | ``` 79 | 80 | ### images_enabled 81 | 82 | 此属性可以设置图片是否加载,默认情况下是加载的。禁用该属性后,可以节省网络流量并提高网页加载速度。但是需要注意的是,禁用图片加载可能会影响JavaScript渲染。 83 | 84 | ```lua 85 | function main(splash, args) 86 | splash.images_enabled = false 87 | splash:go('http://www.baidu.com') 88 | splash:wait(0.5) 89 | splash.js_enabled = false 90 | local title = splash:evaljs('document.title') 91 | return {title=title} 92 | end 93 | ``` 94 | 95 | ### plugins_enabled 96 | 97 | 此属性可以控制浏览器插件是否开启,默认为false。 98 | 99 | `splash.plugins_enabled = false` 100 | 101 | ### scroll_position 102 | 103 | 此属性可以控制页面上下或左右滚动。 104 | 105 | `splash.scroll_position = {y=400}` 106 | 107 | ## Splash对象的方法 108 | 109 | ### go 110 | 111 | 该方法用来请求某个链接,而且它可以模拟GET和POST请求,同时支持传入请求头,表单等数据。 112 | 113 | `ok, reason = splash:go{url, baseurl=nil, headers=nil, http_method='GET', body=nil, formdata=nil}` 114 | 115 | url:请求的URL;baseurl:资源加载相对路径;headers:请求头;http_method:请求方式;body:表单数据;formdata:表单数据 116 | 117 | ### wait 118 | 119 | `splash:wait(2)` 120 | 121 | ### jsfunc 122 | 123 | `local get_div_count = splash:jsfunc()` 124 | 125 | ### evaljs 126 | 127 | 此方法可执行JavaScript代码并返回最后一条JavaScript语句的返回结果 128 | 129 | `result = splash:evaljs('document.title')` 130 | 131 | ### runjs 132 | 133 | 执行JavaScript代码 134 | 135 | `splash:runjs("foo = function() {return 'bar'}")` 136 | 137 | [...具体应用方法见此链接](https://www.cnblogs.com/einsam/p/11416072.html) 138 | 139 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/4.反扒处理/6.4.2_代理池应用.md: -------------------------------------------------------------------------------- 1 | # 代理的使用 2 | 3 | --- 4 | 5 | 我们在做爬虫的过程中经常会遇到这样的情况:最初爬虫正常运行,正常之前数据,一切看起来都很好。但是有时候会报`403 Forbidden`;这时候网页上可能会出现“您的`IP`访问频率太高”这样的提示。出现这个现象的原因是网站采取了反扒措施,服务器会检测某个`IP`在单位时间内的请求次数,如果超过就会拒绝服务,这时候就需要用代理。 6 | 7 | ## 代理池简单实例 8 | 9 | ```mermaid 10 | graph LR 11 | A[爬取ip] --> B[验证ip可用性] 12 | B --> C[保存可以用的ip] 13 | ``` 14 | 15 | 这个只是网络上简单的代理池应用,正规的代理池维护还需要数据库等其他内容,暂时无法找到这方面完整内容。 16 | 17 | ```python 18 | import requests 19 | from fake_useragent import UserAgent 20 | from lxml import etree 21 | import json 22 | 23 | # 在西刺网站上爬取ip,不要用自己的ip爬取太多次,会被封 24 | # xpath爬取的内容是列表,要转化为字典 25 | def get_ip(url): 26 | response = requests.get(url, headers={'User-Agent': UserAgent().chrome}).text 27 | e = etree.HTML(response) 28 | type_ip = e.xpath('//tr/td[6]/text()') 29 | ip = e.xpath('//tr/td[2]/text()') 30 | port = e.xpath('//tr/td[3]/text()') 31 | ip_list = [] 32 | for i in range(len(type_ip)): 33 | ip_dict = {} 34 | ip_dict[type_ip[i]] = ip[i] + ':' + port[i] 35 | ip_list.append(ip_dict) 36 | return ip_list 37 | 38 | # 用百度网站验证ip是否可用 39 | def test_ip(ip_list): 40 | good_ip = [] 41 | i = 1 42 | for ip in ip_list: 43 | print('开始测试第{}个ip'.format(i)) 44 | test_url = 'https://www.baidu.com' 45 | response = requests.get(test_url, headers={'User-Agent': UserAgent().chrome}, proxies=ip, timeout=0.5) 46 | if response.status_code == 200: 47 | del ip['no'] 48 | good_ip.append(ip) 49 | else: 50 | print('该ip不可用') 51 | i += 1 52 | return good_ip 53 | 54 | # 保存ip 55 | def save_ip(good_ip): 56 | with open('ip.txt', 'a') as f: 57 | for ip in good_ip: 58 | f.write(json.dumps(ip) + '\n') 59 | 60 | # 主函数,爬取了2页 61 | def main(): 62 | for i in range(1, 3): 63 | url = 'https://www.xicidaili.com/nn/{}'.format(i) 64 | ip_list = get_ip(url) 65 | good_ip = test_ip(ip_list) 66 | save_ip(good_ip) 67 | 68 | if __name__ == '__main__': 69 | main() 70 | ``` 71 | 72 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/4.反扒处理/6.4.3_模拟登陆.md: -------------------------------------------------------------------------------- 1 | # 模拟登陆 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/5.爬虫框架/6.5.1_PySpider框架基本用法.md: -------------------------------------------------------------------------------- 1 | # PySpider框架基本用法 2 | 3 | --- 4 | 5 | ## 功能简介 6 | 7 | 多进程处理、去重处理、错误重试,代码简介,PyQuery提取,JavaScript渲染、结果监控、WebUI管理。 8 | 9 | ## 安装 10 | 11 | `pip install pyspider` 12 | 13 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/5.爬虫框架/6.5.3_分布式爬虫.md: -------------------------------------------------------------------------------- 1 | # 分布式爬虫 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/5.爬虫框架/6.5.4_分布式爬虫的部署.md: -------------------------------------------------------------------------------- 1 | # 分布式爬虫的部署 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/6.实例应用/6.6.1_Requests+正则表达式爬取猫眼电影top100.md: -------------------------------------------------------------------------------- 1 | # Requests+正则表达式爬取猫眼电影top100 2 | 3 | --- 4 | 5 | ## 目标站点分析 6 | 7 | 在目标网站查看网站源代码,分析需要获取内容包含在哪些标签内。 8 | 9 | ## 流程框架 10 | 11 | 1. 抓取单页内容 12 | 2. 正则表达式 13 | 3. 保存至文件 14 | 4. 开启循环及多线程 15 | 16 | ## 爬虫实战 17 | 18 | ```python 19 | import requests 20 | import re 21 | import json 22 | from requests.exceptions import RequestException 23 | from multiprocessing import Pool 24 | 25 | 26 | def get_one_page(url): 27 | try: 28 | headers = { 29 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36', 30 | 'Referer': 'https://maoyan.com/board/4', 31 | 'Origin': 'https://maoyan.com' 32 | } 33 | response = requests.get(url, headers=headers) 34 | response.raise_for_status() 35 | response.encoding = response.apparent_encoding 36 | return response.text 37 | except RequestException: 38 | return None 39 | 40 | 41 | def parse_one_page(html): 42 | """ 43 | 解析猫眼top100第一页源代码 44 | :param html: 猫眼top100第一页源代码 45 | :return: 格式化的电影信息数据 46 | """ 47 | # 编写正则表达式 48 | pattern = re.compile('
.*?board-index.*?>(\d+)' # 获取排名 49 | + '.*?src="(.*?)".*?src="(.*?)"' # 获取图片链接,有两张图要筛选 50 | + '.*?name">(.*?)' # 获取电影名字 51 | + '.*?star">(.*?)

' # 获取主要演员名字 52 | + '.*?releasetime">(.*?)

' # 获取上映时间 53 | + '.*?integer">(.*?).*?fraction">(.*?).*?
', # 获取分数 54 | re.S) # 无视换行 55 | # 使用正则获取数据 56 | items = re.findall(pattern, html) 57 | # 格式化数据 58 | # img_url = [] 59 | for item in items: 60 | # img_url = img_url.append(item[2]) 61 | yield { 62 | 'index': item[0], 63 | 'image': item[2], 64 | 'title': item[3], 65 | 'actors': item[4].strip()[3:], 66 | 'time': item[5].strip()[5:], 67 | 'score': item[6] + item[7] 68 | } 69 | 70 | 71 | def write_to_file(content): 72 | """ 73 | 格式化的电影信息数据写入本地 74 | :param content: 格式化的电影信息数据 75 | :return: 76 | """ 77 | with open('maoyantop100_1.txt', 'a', encoding='utf8') as f: 78 | f.write(json.dumps(content, ensure_ascii=False) + '\n') 79 | 80 | 81 | def main(offset): 82 | """ 83 | 爬取数据,解析数据,写入本地 84 | :param offset: 页码 85 | :return: 86 | """ 87 | url = 'https://maoyan.com/board/4?offset=' + str(offset) 88 | html = get_one_page(url) 89 | for item in parse_one_page(html): 90 | print(item) 91 | write_to_file(item) 92 | 93 | 94 | if __name__ == '__main__': 95 | # 构造多进程爬取 96 | pool = Pool() 97 | pool.map(main, [i * 10 for i in range(10)]) 98 | ``` 99 | 100 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/6.实例应用/6.6.2_Requests+xpath爬取豆瓣电影top250.md: -------------------------------------------------------------------------------- 1 | # Requests+xpath爬取豆瓣电影top250 2 | 3 | --- 4 | 5 | ```python 6 | import requests 7 | from fake_useragent import UserAgent 8 | from lxml import etree 9 | import json 10 | from multiprocessing import Pool 11 | 12 | # 获取网页源代码 13 | def get_page_code(url): 14 | response = requests.get(url, headers={'User-Agent': UserAgent().chrome}) 15 | response.encoding = 'utf-8' 16 | if response.status_code == 200: 17 | return response.text 18 | 19 | # 获取详细电影信息链接 20 | def get_movie_url(page_code): 21 | e = etree.HTML(page_code) 22 | movie_urls = e.xpath('//div[@class="hd"]/a/@href') 23 | return movie_urls 24 | 25 | # 获取电影信息 26 | def get_movie_info(movie_urls): 27 | movie_infos = [] 28 | for movie_url in movie_urls: 29 | response = requests.get(movie_url, headers={'User-Agent': UserAgent().chrome}) 30 | e = etree.HTML(response.text) 31 | year = e.xpath('//div[@id="info"]/span[@property="v:initialReleaseDate"][1]/text()') 32 | name = e.xpath('//h1/span[1]/text()') 33 | score = e.xpath('//div[@typeof="v:Rating"]/strong/text()') 34 | img_url = e.xpath('//div[@id="mainpic"]/a/img/@src') 35 | movie_info = { 36 | 'year': year, 37 | 'name': name, 38 | 'score': score, 39 | 'img_url': img_url 40 | } 41 | movie_infos.append(movie_info) 42 | return movie_infos 43 | 44 | # 保存电影信息 45 | def save_info(movie_infos): 46 | for movie_info in movie_infos: 47 | with open('doubanTop250.txt', 'a', encoding='utf-8') as f: 48 | f.write(json.dumps(movie_info, ensure_ascii=False) + '\n') 49 | 50 | 51 | def main(i): 52 | url = 'https://movie.douban.com/top250?start={}&filter='.format(i) 53 | page_code = get_page_code(url) 54 | movie_urls = get_movie_url(page_code) 55 | movie_infos = get_movie_info(movie_urls) 56 | save_info(movie_infos) 57 | 58 | 59 | if __name__ == '__main__': 60 | pool = Pool() 61 | pool.map(main, [i * 25 for i in range(10)]) 62 | ``` 63 | 64 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/6.实例应用/6.6.3_分析Ajax来抓取今日头条街拍美图.md: -------------------------------------------------------------------------------- 1 | # 分析Ajax来抓取今日头条街拍美图 2 | 3 | --- 4 | 5 | 有时候我们在用`requests`抓取页面的时候,得到的结果可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据,但是使用`requests`得到的结果并没有。这是因为`requests`获取的都是原始的`HTML`文档,而浏览器中的页面则是经过`JavaScript`处理数据后生成的结果,这些数据的来源有多种,可能是通过`AJax`加载的,可能是包含在`HTML`文档中,也可能是经过`JavaScript`和特定算法生成的。 6 | 7 | 对于第一种情况,数据加载是一种异步加载方式,原始的页面最初不会包含某些数据,原始页面加载完后,会再向服务器请求某个接口获取数据,然后数据才被处理从而呈现到网页上,这其实就是发送一个`Ajax`请求。 8 | 9 | 找`Web`发展的趋势来看,这种形式的页面越来越多。网页的元素`HTML`文档不会包含任何数据,数据都是通过`Ajax`统一加载后在程序出来的,这样在`Web`开发上就可以做到前后端分离,而且降低服务器直接渲染页面代理的压力。所有,遇到这种情况,需要分析网页后台向接口发送的`Ajax`请求,模拟请求获取源代码。 10 | 11 | ## 什么是Ajax 12 | 13 | 全称为Asynchronous JavaScript and XML,即异步的J`avaScript`和`XML`。它不是一门编程语言,而是利用`JavaScript`在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。 14 | 15 | ## 获取Ajax数据的方式 16 | 17 | | 方式 | 优点 | 缺点 | 18 | | ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 19 | | 分析接口,用`requests`获取响应链接 | 直接可以请求到数据,不要要做一些解析工作。代码量少,性能高 | 分析接口比较复杂,特别少通过`js`混淆的接口,要有一定的`js`功底,容易被发现是爬虫 | 20 | | `selenium` | 直接模拟浏览器的行为,浏览器能请求到的,使用`selenium`能请求到,爬虫稳定 | 代码量多,性能低 | 21 | 22 | ## 分析接口获取数据 23 | 24 | 1. 抓取索引页内容 25 | 2. 抓取详情页内容 26 | 3. 下载图片与保存数据库 27 | 4. 开启循环与多线程 28 | 29 | ```python 30 | from urllib.parse import urlencode 31 | import requests 32 | import os 33 | import time 34 | from multiprocessing import Pool 35 | from hashlib import md5 36 | 37 | 38 | # 基础url和请求头信息 39 | base_url = 'https://www.toutiao.com/api/search/content/?' 40 | headers = { 41 | 'Referer': 'https://www.toutiao.com/search/?keyword=%E5%9B%BE%E7%89%87', 42 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36', 43 | 'X-Requested-With': 'XMLHttpRequest', 44 | 'Cookie': 'tt_webid=6804026100667581959; WEATHER_CITY=%E5%8C%97%E4%BA%AC; tt_webid=6804026100667581959; csrftoken=bd43b1b47601e4d2a2e1e143418d047a; ttcid=b334bc3935ae486cacecaeb90c43c7bd27; SLARDAR_WEB_ID=6be7deee-3b7e-4fc3-b933-80b9ef3e934a; s_v_web_id=verify_k7y17xvx_JXDn3y0R_pd7H_47Ow_9dG3_yShA8wX7QWCz; __tasessionId=p53vp50rz1584578659164; tt_scid=ElNCkMU3P.LmI.6-x09lMgCsRockEtxdx5a50beaePY7m3r7ne9z4Rz7.YeDofWY1e89' 45 | } 46 | 47 | 48 | def get_page(offset): 49 | """ 50 | 获取网页数据 51 | :param offset: 偏移量,页码 52 | :return: 53 | """ 54 | timestamp = int(time.time()) 55 | params = { 56 | 'aid': 24, 57 | 'app_name': 'web_search', 58 | 'offset': offset, 59 | 'format': 'json', 60 | 'autoload':'true', 61 | 'keyword': '街拍', 62 | 'count': 20, 63 | 'en_qc': 1, 64 | 'cur_tab': 1, 65 | 'from': 'search_tab', 66 | 'pd': 'synthesis', 67 | 'timestamp': timestamp 68 | } 69 | url = base_url + urlencode(params) 70 | try: 71 | response = requests.get(url, headers=headers) 72 | response.raise_for_status() 73 | # 获取网页数据不对会报错 74 | response.encoding = response.apparent_encoding 75 | # 编码一致 76 | return response.json() 77 | except requests.ConnectionError as e: 78 | print('Error', e.args) 79 | return None 80 | 81 | 82 | def get_images(html): 83 | """ 84 | 获取图片标题和链接 85 | :param html: 网页数据 86 | :return: 87 | """ 88 | if html.get('data'): 89 | # 判断是否有data标签 90 | html = html.get('data') 91 | for item in html: 92 | # 先判断是否有标题和图片链接标签,才能进行下面操作,不然会报NoneType错误 93 | if item.get('title'): 94 | title = item.get('title').replace(' |', ' ').replace('\\', ' ') 95 | if item.get('image_list'): 96 | for image_urls in item.get('image_list'): 97 | # 获得image_list里每一条的图片 98 | image_url = image_urls['url'] 99 | yield { 100 | 'title': title, 101 | 'image': image_url 102 | } 103 | else: 104 | print('没有获取到数据') 105 | 106 | 107 | def save_image(item): 108 | """ 109 | 保存图片 110 | :param item: 标题和图片链接 111 | :return: 112 | """ 113 | img_path = 'images' + '/' + item.get('title') 114 | # 设置图片保存路径 115 | if not os.path.exists(img_path): 116 | try: 117 | os.mkdir(img_path) 118 | except OSError: 119 | # 这里有报错,没有解决 120 | print('文件命名错误') 121 | try: 122 | response = requests.get(item.get('image')) 123 | response.raise_for_status() 124 | file_path = '{0}/{1}.{2}'.format(img_path, md5(response.content).hexdigest(), 'jpg') 125 | if not os.path.exists(file_path): 126 | with open(file_path, 'wb') as f: 127 | f.write(response.content) 128 | else: 129 | print('已经存在', file_path) 130 | except requests.ConnectionError: 131 | print('下载不成功') 132 | except OSError: 133 | # 没有解决有些图片下载下来文件夹名是乱码,只能跳过 134 | print('图片名称格式不对') 135 | 136 | 137 | def main(offset): 138 | """ 139 | 主程序执行 140 | :param offset: ajax分页请求参数 141 | :return: 142 | """ 143 | html = get_page(offset) 144 | # 获取网页数据 145 | for item in get_images(html): 146 | # 获取图片标题和图片链接 147 | save_image(item) 148 | # 保存图片 149 | 150 | 151 | GROUP_START = 0 152 | GROUP_END = 10 153 | 154 | 155 | if __name__ == '__main__': 156 | pool = Pool() 157 | group = ([x * 20 for x in range(GROUP_START, GROUP_END + 1)]) 158 | pool.map(main, group) 159 | pool.close() 160 | pool.join() 161 | ``` 162 | 163 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/6.实例应用/6.6.4_Selenium爬取淘宝美食.md: -------------------------------------------------------------------------------- 1 | # Selenium + Chrome/PhantomJS爬取淘宝美食 2 | 3 | --- 4 | 5 | ## 流程框架 6 | 7 | 1. 搜索关键词 8 | 2. 分析页面并翻页 9 | 3. 分析提取商品内容 10 | 4. 存储到mongdb 11 | 12 | 用户名密码可以输入,但是滑块验证码过不了 13 | 14 | ```python 15 | from selenium import webdriver 16 | from selenium.common.exceptions import TimeoutException 17 | from selenium.webdriver.common.by import By 18 | from selenium.webdriver.support import expected_conditions as EC 19 | from selenium.webdriver.support.wait import WebDriverWait 20 | from urllib.parse import quote 21 | from pyquery import PyQuery as pq 22 | import time 23 | from selenium.webdriver.common.action_chains import ActionChains 24 | 25 | 26 | # 声明配置好的浏览器对象 27 | browser = webdriver.Chrome() 28 | # 等待反应(需要手动扫码登陆) 29 | wait = WebDriverWait(browser, 20) 30 | text = 'iPhoneXR' 31 | 32 | 33 | def login_page(): 34 | login_url = 'https://login.taobao.com/member/login.jhtml?' 35 | browser.get(login_url) 36 | browser.find_element_by_xpath('//*[@id="TPL_username_1"]').send_keys('我逗你玩哼') 37 | browser.find_element_by_xpath('//*[@id="TPL_password_1"]').send_keys('tq58215318123') 38 | browser.find_element_by_xpath('//*[@id="J_SubmitStatic"]').click() 39 | time.sleep(2) 40 | button = browser.find_element_by_xpath('//*[@id="J_SubmitStatic"]') 41 | ActionChains(browser).click_and_hold(on_element=button).perform() 42 | ActionChains(browser).move_to_element_with_offset(to_element=button, xoffset=100, yoffset=0).perform() 43 | 44 | 45 | def index_page(page): 46 | ''' 47 | 获取索引页 48 | :param page: 49 | :return: 50 | ''' 51 | print('正在爬取第', page,'页') 52 | try: 53 | # 网址url 54 | url = 'https://s.taobao.com/search?q='+ quote(text) 55 | browser.get(url) 56 | if page > 1: 57 | #找到最下面的页码标签 58 | input = wait.until( 59 | EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager div.form > input')) 60 | ) 61 | submit = wait.until( 62 | EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager div.form > span.btn.J_Submit')) 63 | ) 64 | input.clear() 65 | input.send_keys(page) 66 | #模拟点击确认 67 | submit.click() 68 | # 找到每页数据的标签 69 | wait.until( 70 | EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#mainsrp-pager li.item.active > span'), str(page)) 71 | ) 72 | wait.until( 73 | EC.presence_of_element_located((By.CSS_SELECTOR, '.m-itemlist .items .item')) 74 | ) 75 | # 调用函数,获取数据 76 | get_products() 77 | except TimeoutException: 78 | index_page(page) 79 | 80 | 81 | def get_products(): 82 | ''' 83 | 提取商品数据 84 | :return: 85 | ''' 86 | # page_source获取网页源代码 87 | html = browser.page_source 88 | doc = pq(html) 89 | items = doc('#mainsrp-itemlist .items .item').items() 90 | for item in items: 91 | # 数据存入字典 92 | product = { 93 | 'image': item.find('.pic .img').attr('data-src'), 94 | 'price': item.find('.price').text(), 95 | 'deal': item.find('.deal-cnt').text(), 96 | 'title': item.find('.title').text(), 97 | 'shop': item.find('.shop').text(), 98 | 'location': item.find('.location').text(), 99 | } 100 | print(product) 101 | #主函数 102 | def main(): 103 | ''' 104 | 遍历每一页 105 | :return: 106 | ''' 107 | for i in range(1, 101): 108 | index_page(i) 109 | #关闭浏览器 110 | browser.close() 111 | 112 | if __name__ == '__main__': 113 | main() 114 | ``` 115 | 116 | -------------------------------------------------------------------------------- /notes/第5章 Python爬虫/6.实例应用/6.6.5_Scrapy+mongodb爬取链家二手房信息.md: -------------------------------------------------------------------------------- 1 | # Scrapy+mongodb爬取链家二手房信息 2 | 3 | --- 4 | 5 | ```python 6 | # 创建项目 7 | scrapy startproject room 8 | cd room 9 | scrapy genspider lianjia lianjia.com 10 | ``` 11 | 12 | ```python 13 | # settings 14 | from fake_useragent import UserAgent 15 | 16 | USER_AGENT = UserAgent().random 17 | ROBOTSTXT_OBEY = False 18 | DOWNLOAD_DELAY = 1 19 | ITEM_PIPELINES = { 20 | 'room.pipelines.MongoPipeline': 300, 21 | } 22 | LOG_LEVEL = 'ERROR' 23 | ``` 24 | 25 | ```python 26 | # start 27 | from scrapy.cmdline import execute 28 | 29 | execute('scrapy crawl lianjia'.split()) 30 | ``` 31 | 32 | ```python 33 | # spider 34 | import scrapy 35 | 36 | class LianjiaSpider(scrapy.Spider): 37 | name = 'lianjia' 38 | # allowed_domains = ['lianjia.com'] 39 | start_urls = ['https://sh.lianjia.com/ershoufang/pg{}/'.format(i) for i in range(1, 3)] 40 | 41 | def parse(self, response): 42 | urls = response.xpath('//div[@class="info clear"]/div[@class="title"]/a/@href').extract() 43 | for url in urls: 44 | yield scrapy.Request(url, callback=self.parse_info) 45 | 46 | def parse_info(self, response): 47 | total = response.xpath('concat(//span[@class="total"]/text(),//span[@class="unit"]/span/text())').extract_first() 48 | unit_price = response.xpath('string(//span[@class="unitPriceValue"])').extract_first() 49 | mian_ji = response.xpath('//div[@class="area"]/div[1]/text()').extract_first() 50 | fang_xin = response.xpath('//div[@class="room"]/div[1]/text()').extract_first() 51 | yield { 52 | 'total': total, 53 | 'unit_price': unit_price, 54 | 'mian_ji': mian_ji, 55 | 'fang_xin': fang_xin 56 | } 57 | ``` 58 | 59 | ```python 60 | # pipelines 61 | import pymongo 62 | 63 | class MongoPipeline(object): 64 | def open_spider(self, spider): 65 | self.client = pymongo.MongoClient() 66 | 67 | def process_item(self, item, spider): 68 | self.client.room.lianjia.insert(item) 69 | return item 70 | 71 | def close_spider(self, spider): 72 | self.client.close() 73 | ``` 74 | 75 | -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.1_网络编程基础/7.1.1_网络编程的基本概念.md: -------------------------------------------------------------------------------- 1 | # 网络编程的基本概念 2 | 3 | --- 4 | 5 | 自从互联网诞生以来,一直都是在快速发展,现在几乎所有的程序都是网络程序,如手机应用、网站等。计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信。网络编程就是如何在程序中实现两台计算机的通信。 6 | 7 | 计算机除了安装浏览器外,还可以安装`QQ`,微信、网盘、邮件客户端等,不同的程序连接的计算机也会不同。确切的说,网络通信是两台计算机上的两个进程之间的通信。例如,浏览器进程和新浪服务器上的某个Web服务进程在通信,而`QQ`进程是与腾讯的某个服务器上的某个进程在通信。 8 | 9 | ## 网络基础知识 10 | 11 | 计算机和计算机之间是通过两个软件进程链接起来的。但如果要让这两个进程之间进行通信,还需要解决很多问题。`OSI`参考模型解决两个进程通信问题的方法是先分层,简单来说,这两个进程之间的通信是通过七大部分来完成的,也就是`OSI`七层参考模型。 12 | 13 | 开放系统互联(`Open System Interconnection`)七层网络模型称为开放式系统互联参考模型,是把网络通信在逻辑上定义,也可以理解为定义了通用的网络通信规范。而数据在网络中传输的过程,实际就是封装和解封装的过程。发送方通过各种封装处理,把数据转换成比特流的形式,比特流在信号传输的硬件媒介中传输,接收方再把比特流进行解封装处理。 14 | 15 | ![OSI七层模型](D:\repository\PythonNotes\notes\第7章 网络编程\images\OSI七层模型.png) 16 | 17 | 把用户的应用程序作为最高层,把物理通信线路作为最底层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。但`OSI`模型是一个理论上的网络通信模型。目前主要用于教学理解。在实际使用中,网络硬件基本都是参考`TCP/IP`模型。可以把`TCP/IP`模型理解为`OSI`模型的简化版本。从概念上来讲,`TCP/IP`协议族则把7层网络模型合并为4层,模型如下图。 18 | 19 | ![网络分层模型](D:\repository\PythonNotes\notes\第7章 网络编程\images\网络分层模型.jpg) 20 | 21 | ## 网络基本概念 22 | 23 | ### `IP`地址 24 | 25 | `IP`地址用来表示计算机等网络设备的网络地址。`IP`地址分为`IPv4`和`IPv6`两大类,当前广泛使用的是`IPv4`.目前`IPv4`几乎耗尽,下一阶段必然会进行版本升级到`IPv6`.如果无特别注明,人们使用的`IP`地址所指的就是`IPv4`。 26 | 27 | `IP`地址由32位二进制数组成,分为4段,每一段为8位二进制数,中间使用英文的标点符号“.”隔开。由于二进制数太长,为了便于记忆和识别,把每一段8位二进制数转换为十进制,大小为0~255。`IP`地址的这种表示法称为“点分十进制表示法”。`IP`地址可以表示为182.168.1.10. 28 | 29 | Windows查看`IP`地址 `ipconfig` 30 | 31 | Linux查看`IP`地址 `ifconfig` 32 | 33 | ### 主机名 34 | 35 | 主机名是计算机的名称,因特网上的`Web`站点由主机名识别。主机名有时也称为域名。主机名映射到`IP`地址,如博客园的地址是www.cnblogs.com。在因特网上`IP`地址和主机名是一一对应的,通过域名解析可以由主机名得到计算机的`IP`地址。可以通过`ping`域名命令得到域名映射的`IP`地址。 36 | 37 | ### 端口号 38 | 39 | 端口号是网络通信时同一机器上的不同进程的标识。端口号是为了在一台主机上提供更多的网络资源而采取的一种手段。其中0~1023是公认端口号,是为已经公认定义的软件保留的。例如,21端口分配给FTP服务,25端口分配给`SMTP`(简单邮件传输协议)服务,80端口分配给HTTP服务。 40 | 41 | 1024~65535是没有公共定义分端口号,用户可以自定义这些端口的作用。 42 | 43 | Windows查看端口占用情况:`netstat -ano | findstr 3306` 44 | 45 | Linux查看端口占用情况:`netstat -ano | grep 3306` 46 | 47 | ## 网络传输协议 48 | 49 | `TCP/IP(Transmission Control Protocol/Internet Protocol)`即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何在他们之间传输的标准。 50 | 51 | TCP是传输控制协议,是面向连接的,并且是一种可靠的协议。在基于TCP进行通信时,通信双方需要先建立一个TCP连接。建立连接时需要经过3次 握手,握手成功才可以进行通信。使用TCP协议传输,每次收发数据之前必须通过Connect()建立连接,这也是双向的,即任何一方都可以收发数据。协议本身提供了一些保障机制以保证它是可靠的、有序的,即每个包括按照发送的顺序到达接收方。 52 | 53 | `UDP(User Datagram Protocol)`是用户数据报协议,是无连接的,不可靠的传输协议。`UDP`和TCP位于同一个传输层,但是`UDP`不保证数据包的传输顺序,也就是说,`UDP`传输不保证数据的正确性,`UDP`可能会丢包。当一个Socket(通常是Server Socket)等待建立连接时,另一个Socket可以要求进行连接,一旦两个Socket连接起来,就可以用`Sendto`发送数据,也可以用`Recvfrom`接收数据。根本不关心对方是否存在,是否发送了数据。它的特点是传输数据是比较快。 -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.1_网络编程基础/7.1.3_HTTP协议.md: -------------------------------------------------------------------------------- 1 | # HTTP协议 2 | 3 | > 笔记来自网络 4 | 5 | --- 6 | 7 | `HTTP`协议在栈中的位置: 8 | 9 | ![img](https://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy8xMTM2MDkwLzIwMTcwOS8xMTM2MDkwLTIwMTcwOTE0MDk1NzU3Njg4LTE2NzY4NTgzNzkucG5n.jpg) 10 | 11 | `HTTP`是在网络上传输`HTML`的协议,用于浏览器和服务器的通信,以明文方式发送内容,不提供任何方式的数据加密。 12 | 13 | 在WEB应用中,服务器把网页传给浏览器,实际上就是把网页的`HTML`代码发送给浏览器,让浏览器渲染出来。 14 | 15 | `HTTP`协议的主要特点: 16 | 17 | 1、支持客户/服务器模式 18 | 19 | 2、简单快速:客户端向服务器请求服务时,只需发送请求方法和路径 20 | 21 | 3、灵活:`HTTP`允许传输任意类型的数据对象 22 | 23 | 4、无连接:限制每次连接只处理一个请求,服务器处理完客户的请求并收到客户的应答后,就会断开连接 24 | 25 | 5、无状态:是指协议对于事务处理没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则必须重传,这样可能导致每次连接传送的数据量增大,所以`cookie`是为了解决这个问题 26 | 27 | **http://120.77.171.182:80/** 28 | 29 | `http`表示要通过`HTTP`协议来定位网络资源; 30 | 31 | `120.77.171.182`表示合法的`IP`地址,当然也可以是主机域名; 32 | 33 | `80`是指定的一个端口号,省略了也会默认`80`端口; 34 | 35 | 通常有一些`url`地址会在端口号后面跟上`/index.html`之类,端口之后的是请求资源的`URI`;如果没有,浏览器会自动以`/`的形式给出。 36 | 37 | 在地址栏输入http://120.77.171.182/ 38 | 39 | 浏览器发给服务器的请求 40 | 41 | ![img](https://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy8xMTM2MDkwLzIwMTcwOS8xMTM2MDkwLTIwMTcwOTE0MTAyMjM3ODI4LTExNTMzNzQ2MjgucG5n.jpg) 42 | 43 | `GET`表示一个读取请求,将从服务器获得网页数据,`/`表示`URL`的路径,`URL`总是以`/`开头,`/`就表示首页,最后的`HTTP/1.1`指示采用的`HTTP`协议版本是1.1。 44 | 45 | `Host`表示请求的域名 46 | 47 | 显示服务器返回的原始响应数据 48 | 49 | ![img](https://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy8xMTM2MDkwLzIwMTcwOS8xMTM2MDkwLTIwMTcwOTE0MTAyMjU4MTU3LTE0MzIwMjQzMjUucG5n.jpg) 50 | 51 | 200表示一个成功的响应,后面的`OK`是状态描述。 52 | 53 | 浏览器就是依靠`Content-Type`来判断响应的内容是网页还是图片,是视频还是音乐。 54 | 55 | 当浏览器读取到新浪首页的`HTML`源码后,它会解析`HTML`,显示页面,然后,根据`HTML`里面的各种链接,再发送`HTTP`请求给新浪服务器,拿到相应的图片、视频、Flash、JavaScript脚本、`CSS`等各种资源,最终显示出一个完整的页面。 56 | 57 | HTTP请求流程 58 | 59 | 步骤1:浏览器首先向服务器发送HTTP请求,请求包括: 60 | 61 | 方法:GET还是POST,GET仅请求资源,POST会附带用户数据; 62 | 63 | 路径:`/full/url/path;` 64 | 65 | 域名:由Host头指定:`Host: 120.77.171.182` 66 | 67 | 以及其他相关的Header; 68 | 69 | 如果是POST,那么请求还包括一个Body,包含用户数据。 70 | 71 | 步骤2:服务器向浏览器返回HTTP响应,响应包括: 72 | 73 | 响应代码:200表示成功,`3xx`表示重定向,`4xx`表示客户端发送的请求有错误,`5xx`表示服务器端处理时发生了错误; 74 | 75 | 响应类型:由`Content-Type`指定;`text/html`是纯网页内容、`text/plain`是纯文本、`image/jpeg`是图片资源 76 | 77 | 以及其他相关的Header; 78 | 79 | 通常服务器的HTTP响应会携带内容,也就是有一个Body,包含响应的内容,网页的HTML源码就在Body中。 80 | 81 | 步骤3:如果浏览器还需要继续向服务器请求其他资源,比如图片,就再次发出HTTP请求,重复步骤1、2。 82 | 83 | **`HTTPS`协议** 84 | 85 | 是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入`SSL`层。 86 | 87 | 一般意义上的`https`,就是服务器有一个证书 88 | 89 | `http`和`https`的对比 90 | 91 | ![img](https://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy8xMTM2MDkwLzIwMTcwOS8xMTM2MDkwLTIwMTcwOTE0MTAzMDAxMjAzLTEzOTQyMDA2MDIucG5n.jpg) ![img](https://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy8xMTM2MDkwLzIwMTcwOS8xMTM2MDkwLTIwMTcwOTE0MTAzMDA5ODYwLTE1MDA3MzAxNjYucG5n.jpg) 92 | 93 | HTTP和`HTTPS`的区别: 94 | 95 | ![img](https://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy8xMTM2MDkwLzIwMTcwOS8xMTM2MDkwLTIwMTcwOTE0MTAzMTI2NjEwLTUxNTY3ODc2Ni5wbmc=.jpg) -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.1_网络编程基础/7.1.4_搭建Python自带Web服务器.md: -------------------------------------------------------------------------------- 1 | # 搭建Python自带Web服务器 2 | 3 | --- 4 | 5 | 1. 静态Web服务器是什么? 6 | 7 | 可以为发出请求的浏览器提供静态文档的程序。平时我们浏览百度新闻数据的时候,每天的新闻数据都会发生变化,那访问的这个页面就是动态的,而我们开发的是静态的,页面的数据不会发生变化。 8 | 9 | 2. 如何搭建Python自带的静态Web服务器 10 | 11 | 搭建Python自带的静态Web服务器使用 12 | 13 | `python3 -m http.server 端口号` 14 | 15 | `-m`:表示运行包里面的模块,执行这个命令的时候,需要进入你自己指定静态文件的目录,然后通过浏览器就能访问对于的`html`文件,这样一个静态Web服务器就搭建好了。 16 | 17 | ## 返回固定页面的Web服务器 18 | 19 | ```python 20 | import socket 21 | 22 | 23 | def server_client(new_socket): 24 | request = new_socket.recv(1024) 25 | print(request) 26 | response = "HTTP/1.1 200 OK \r\n" 27 | response += "\r\n" 28 | response += "hahah" 29 | new_socket.send(response.encode("utf-8")) 30 | new_socket.close() 31 | 32 | 33 | def main(): 34 | # 创建套接字 35 | tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 36 | # 绑定 37 | tcp_server_socket.bind(("", 2333)) 38 | # 变为监听套接字 39 | tcp_server_socket.listen(128) 40 | # 等待新的客户端连接 41 | new_socket, client_addr = tcp_server_socket.accept() 42 | # 为这个客户端服务 43 | server_client(new_socket) 44 | 45 | 46 | if __name__ == '__main__': 47 | main() 48 | ``` 49 | 50 | ## 返回浏览器需要的Web页面 51 | 52 | ```python 53 | import socket 54 | 55 | 56 | def server_client(new_socket): 57 | request = new_socket.recv(1024).decode("utf-8") 58 | print(request) 59 | response = "HTTP/1.1 200 OK \r\n" 60 | response += "\r\n" 61 | # response += "hahah" 62 | f = open("./html/index.html", "rb") 63 | html_content = f.read() 64 | f.close() 65 | new_socket.send(response.encode("utf-8")) 66 | new_socket.send(html_content) 67 | new_socket.close() 68 | 69 | 70 | def main(): 71 | # 创建套接字 72 | tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 73 | # 绑定 74 | tcp_server_socket.bind(("", 2333)) 75 | # 变为监听套接字 76 | tcp_server_socket.listen(128) 77 | # 等待新的客户端连接 78 | new_socket, client_addr = tcp_server_socket.accept() 79 | # 为这个客户端服务 80 | server_client(new_socket) 81 | 82 | 83 | if __name__ == '__main__': 84 | main() 85 | ``` 86 | 87 | ## 动态Web服务器 88 | 89 | ```python 90 | import socket 91 | from multiprocessing import Process 92 | import re 93 | import sys 94 | 95 | 96 | htmlRootDir = "/Users/huxiaoyi/Desktop/" 97 | WSGIPYTHONPACH = "/Users/huxiaoyi/Desktop/wsgipy/" 98 | class HTTPServers(object): 99 | def __init__(self,port): 100 | self.serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 101 | self.serverSocket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1 ) 102 | self.serverSocket.bind(("",port)) 103 | 104 | def start(self): 105 | self.serverSocket.listen(128) 106 | while True: 107 | clientSocket,clientAddress = self.serverSocket.accept() 108 | hadleClientProcess = Process(target=self.handleClient,args=(clientSocket,)) 109 | hadleClientProcess.start() 110 | clientSocket.close() 111 | 112 | def startResponse(self,status,headers): 113 | responseHeaders = "HTPP/1.1" + status + "\r\n" 114 | for header in headers: 115 | responseHeaders += "%s:%s\r\n" %header 116 | self.responseHeaders = responseHeaders 117 | print(self.responseHeaders) 118 | 119 | def handleClient(self,clientSocket): 120 | requestData = clientSocket.recv(1024) 121 | print (requestData) 122 | requestDataLines = requestData.splitlines() 123 | for line in requestDataLines: 124 | print(line) 125 | requestStartline = requestDataLines[0] 126 | print (requestStartline) 127 | #提取用户请求的文件名 128 | fileName = re.match(r"\w+ +(/[^ ]*) ",requestStartline.decode("utf-8")).group(1) 129 | if fileName.endswith(".py"): 130 | m = __import__(fileName[1:-3]) 131 | env = {} 132 | responseBody = m.application(env,self.startResponse) 133 | response = self.responseHeaders + "\r\n" + responseBody 134 | print("此处有问题") 135 | print(response) 136 | else: 137 | if "/" == fileName: 138 | fileName = "index.html" 139 | try: 140 | file = open(htmlRootDir + fileName,"rb") 141 | except IOError: 142 | responseStart = "HTTP/1.1 404 Not Found" 143 | responseHeaders = "Server:Huyankai Servers" 144 | responseBody = "This page is Not Found" 145 | else: 146 | fileData = file.read() 147 | file.close() 148 | responseStart = "HTTP/1.1 200 OK\r\n" 149 | responseHeaders = "Server:Huyankai Servers\r\n" 150 | responseBody = fileData.decode("utf-8") 151 | response = responseStart + responseHeaders + "\r\n" +responseBody 152 | print(response) 153 | clientSocket.send(bytes(response,"utf-8")) 154 | clientSocket.close() 155 | 156 | 157 | def main(): 158 | sys.path.insert(1,WSGIPYTHONPACH) 159 | httpServer = HTTPServers(8050) 160 | httpServer.start() 161 | 162 | 163 | if __name__ == "__main__": 164 | main() 165 | ``` 166 | 167 | -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.2_前端网络编程/7.2.1_HTML/8.1.1.1_Web语言:认识HTML.md: -------------------------------------------------------------------------------- 1 | # Web语言:认识HTML 2 | 3 | --- 4 | 5 | ## Web让广播明显黯然失色 6 | 7 | 要建立web页面,需要创建用超文本标记语言(Hyper Text Markup Language,简写为HTML)编写的文件,把它们放在一个Web服务器上。 8 | 9 | 一旦把文件放在web服务器上,任何浏览器就能通过互联网得到你的web页面。 10 | 11 | 根据web页面的HTML,浏览器可以了解到显示页面所需要的全部信息。另外,如果编写得足够好,你的网页甚至在手机和移动设备上就能很好地显示,还允许有视觉缺陷的人在语音浏览器和屏幕放大器上查看。 12 | 13 | 大量PC和其他设备已经连接到互联网,它们都运行组web浏览器。更重要的是,我们的朋友,家人,粉丝和潜在客户可能正在使用这些设备。 14 | 15 | ## Web服务器能做什么? 16 | 17 | Web服务器在互联网上有一根全天候的工作,夜以继日、不知疲倦地等待来自Web浏览器的请求。什么类型的请求?可能是请求Web页面、图像或声音,或者可能甚至是一个视频。服务器收到这些资源请求时,会查找所请求的资源,然后把找到的资源发回给浏览器。 18 | 19 | ## Web浏览器能做什么? 20 | 21 | 你已经知道浏览器是如何工作的:你在网上冲浪,单机一个链接来访问某个页面。这个单机会导致浏览器向Web服务器请求一个HTML页面,获取这个页面,并在你的浏览器窗口中显示。 22 | 23 | 但是浏览器怎么知道如何显示一个页面呢?这里就要用到HTML了。HTML会告诉浏览器页面的所有内容和结构。 24 | 25 | ## 你写的代码HTML 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | Head First Lounge 33 | 34 | 35 |

Welecome to the Head First Lounge

36 | 37 |

38 | Join us any evening for refreshing elixirs, 39 | conversation and maybe a game or 40 | two of Dance Dance Revolution 41 | Wireless access is always provided; 42 | BYOWS (Bring your own Web server). 43 |

44 |

Directions

45 |

46 | You'll find us right in the center of downtown Webville. Come join us! 47 |

48 | 49 | 50 | ``` 51 | 52 | 我们并不指望你对HTML很了解。目前只需要你对HTML有个初步的认识,稍后我们会循序渐进地详细介绍所有内容。 53 | 54 | ## 浏览器创建的页面 55 | 56 | 浏览器读到你的HTML时,他会翻译文本中的所有标记。标记就是尖括号括起来的词或字符。例如`,

,

`等。标记会告诉浏览器文本的结构和含义。所有并不是交给浏览器一大堆文本,利用HTML,你可以标记告诉浏览器哪些文本是标题,哪些文本是段落,哪些文本需要强调,或者图像需要放在什么位置。 57 | 58 | ![1](D:\repository\PythonNotes\notes\第7章 网络编程\images\1.png) 59 | 60 | 创建Starbuzz web页面 61 | 62 | ```html 63 | 64 | 65 | 66 | 67 | Starbuzz Coffee 68 | 78 | 79 |

Starbuzz Coffee Beverages

80 |

House Blend, $1.49

81 |

82 | A smooth, mild blend of coffees from Mexico, Bolivia and Guatemala 83 |

84 |

Mocha Cafe Latte, $2.35

85 |

86 | Espresso, steamed milk and chocolate syrup. 87 |

88 |

Cappuccino, $1.89

89 |

90 | A mixture of espresso, steamed milk and foam. 91 |

92 |

Chai Tea, $1.85

93 |

94 | A spicy drink made with black tea, spices, milk and honey. 95 |

96 | 97 | 98 | 99 | ``` 100 | 101 | ![2](D:\repository\PythonNotes\notes\第7章 网络编程\images\2.png) -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.2_前端网络编程/7.2.1_HTML/8.1.1.2_认识HTML中的HT:深入了解超文本.md: -------------------------------------------------------------------------------- 1 | # 认识HTML中的HT:深入了解超文本 2 | 3 | --- 4 | 5 | 实现页面之间的相互跳转 6 | 7 | ```html 8 | 9 | 10 | 11 | Head First Lounge 12 | 13 | 14 |

Welcome to the New and Improved Head First Lounge

15 | 16 |

17 | Join us any evening for 18 | refreshing elixirs, 19 | conversation and maybe a game or two of 20 | Dance Dance Revolution. 21 | Wireless access is always provided; 22 | BYOWS (Bring your own web server). 23 |

24 |

Directions

25 |

26 | You'll find us right in the center of downtown Webville. 27 | If you need help finding us, check out 28 | our detailed directions. 29 | Come join us! 30 |

31 | 32 | 33 | ``` 34 | 35 | ```html 36 | 37 | 38 | 39 | Head First Lounge Elixirs 40 | 41 | 42 |

Our Elixirs

43 | 44 |

Green Tea Cooler

45 |

46 | 47 | Chock full of vitamins and minerals, this elixir 48 | combines the healthful benefits of green tea with 49 | a twist of chamomile blossoms and ginger root. 50 |

51 |

Raspberry Ice Concentration

52 |

53 | 54 | Combining raspberry juice with lemon grass, 55 | citrus peel and rosehips, this icy drink 56 | will make your mind feel clear and crisp. 57 |

58 |

Blueberry Bliss Elixir

59 |

60 | 61 | Blueberries and cherry essence mixed into a base 62 | of elderflower herb tea will put you in a relaxed 63 | state of bliss in no time. 64 |

65 |

Cranberry Antioxidant Blast

66 |

67 | 68 | Wake up to the flavors of cranberry and hibiscus 69 | in this vitamin C rich elixir. 70 |

71 |

72 | Back to the Lounge 73 |

74 | 75 | 76 | ``` 77 | 78 | ```html 79 | 80 | 81 | 82 | Head First Lounge Directions 83 | 84 | 85 |

Directions

86 |

Take the 305 S exit to Webville - go 0.4 mi

87 |

Continue on 305 - go 12 mi

88 |

Turn right at Structure Ave N - go 0.6 mi

89 |

Turn right and head toward Structure Ave N - go 0.0 mi

90 |

Turn right at Structure Ave N - go 0.7 mi

91 |

Continue on Structure Ave S - go 0.2 mi

92 |

Turn right at SW Presentation Way - go 0.0 mi

93 |

94 | Back to the Lounge 95 |

96 | 97 | 98 | ``` 99 | 100 | -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.2_前端网络编程/7.2.1_HTML/8.1.1.3_Web页面建设:构建模块.md: -------------------------------------------------------------------------------- 1 | # Web页面建设:构建模块 2 | 3 | --- 4 | 5 | ```html 6 | 7 | 8 | My Trip Around the USA on a Segway 9 | 10 | 11 | 12 |

Segway'n USA

13 |

14 | Documenting my trip around the US on my very own Segway! 15 |

16 | 17 |

August 20, 2012

18 | 19 |

20 | Well I made it 1200 miles already, and I passed 21 | through some interesting places on the way: 22 |

23 | 24 |
    25 |
  1. Walla Walla, WA
  2. 26 |
  3. Magic City, ID
  4. 27 |
  5. Bountiful, UT
  6. 28 |
  7. Last Chance, CO
  8. 29 |
  9. Truth or Consequences, NM
  10. 30 |
  11. Why, AZ
  12. 31 |
32 | 33 |

July 14, 2012

34 |

35 | I saw some Burma Shave style signs on the side of the 36 | road today: 37 |

38 |
39 | Passing cars,
40 | When you can't see,
41 | May get you,
42 | A glimpse,
43 | Of eternity.
44 |
45 |

46 | I definitely won't be passing any cars. 47 |

48 | 49 |

June 2, 2012

50 | 51 |

52 | My first day of the trip! I can't believe I finally got 53 | everything packed and ready to go. Because I'm on a Segway, 54 | I wasn't able to bring a whole lot with me: 55 |

56 |
    57 |
  • cellphone
  • 58 |
  • iPod
  • 59 |
  • digital camera
  • 60 |
  • and a protein bar
  • 61 |
62 |

63 | Just the essentials. As 64 | Lao Tzu would have said, A journey of a 65 | thousand miles begins with one Segway. 66 |

67 | 68 | 69 | ``` 70 | 71 | 这是编写自己旅游日记的网页代码,主要的新内容有: 72 | 73 | `ol`:有序标签 74 | 75 | `ul`:无序标签 76 | 77 | `blockquote`:块引用 78 | 79 | `q`:短引用 80 | 81 | `br`:换行 -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.2_前端网络编程/7.2.1_HTML/8.1.1.4_Web镇之旅:连接起来.md: -------------------------------------------------------------------------------- 1 | # Web镇之旅:连接起来 2 | 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.2_前端网络编程/7.2.1_HTML/传智html基础/JavaScript基础.md: -------------------------------------------------------------------------------- 1 | # JavaScript基础 2 | 3 | --- 4 | 5 | ## JavaScript的介绍 6 | 7 | ### JavaScript的定义 8 | 9 | JavaScript是运行在浏览器端的脚本语言,是由浏览器解释执行的,检查js。它能够让网页和用户有交互功能,增加良好的用户体验效果。 10 | 11 | 前端开发三大模块: 12 | 13 | 1. HTML:负责网页结构 14 | 2. CSS:负责网页样式 15 | 3. JavaScript:负责网页行为 16 | 17 | ## JavaScript的使用方式 18 | 19 | 1. 行内式(主要用于事件) 20 | 21 | 2. 内嵌式 22 | 23 | 3. 外链式 24 | 25 | ```html 26 | 27 | 28 | 29 | 30 | 31 | Document 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ``` 47 | 48 | ```js 49 | alert('我是外链式的js代码'); 50 | ``` 51 | 52 | ## 变量和数据类型 53 | 54 | ### 定义变量 55 | 56 | JavaScript是一种弱类型语言,也就是说不需要指定变量的类型,JavaScript的变量类型由它的值来决定,定义变量需要用关键字`var`,一条JavaScript语句应该以`;`结尾。 57 | 58 | 定义变量的语法格式: 59 | 60 | `var 变量名 = 值;` 61 | 62 | ### JavaScript注释 63 | 64 | `单行注释 // 多行注释 /* */ ` 65 | 66 | ### 数据类型 67 | 68 | ![JavaScript数据类型](D:\repository\PythonNotes\notes\第7章 网络编程\images\JavaScript数据类型.png) 69 | 70 | ### 变量命名规范 71 | 72 | 1. 区分大小写 73 | 2. 第一个字符必须是字母,下划线或者美元符号 74 | 3. 其他字符可以是字母,数字,下划线或美元符号 75 | 76 | ### 匈牙利命名风格 77 | 78 | ![匈牙利命名风格](D:\repository\PythonNotes\notes\第7章 网络编程\images\匈牙利命名风格.png) 79 | 80 | ## 函数定义和调用 81 | 82 | ### 函数定义 83 | 84 | 函数就是可以重复使用的代码块,使用关键字`function`定义函数。 85 | 86 | ### 函数的基本使用 87 | 88 | ```html 89 | 90 | 91 | 92 | 93 | 94 | Document 95 | 96 | 117 | 118 | 119 | 120 | 121 | 122 | ``` 123 | 124 | ## 变量作用域 125 | 126 | ### 变量作用域的介绍 127 | 128 | 变量作用域就是变量的使用范围,变量分为: 129 | 130 | - 局部变量 131 | - 全局变量 132 | 133 | ### 局部变量和全局变量 134 | 135 | 局部变量是函数内部使用的变量,而全局变量在函数外定义的变量,可以在不同函数内使用,并且不同函数内可以共享变量。 136 | 137 | ```html 138 | 139 | 140 | 141 | 142 | 143 | Document 144 | 145 | 168 | 169 | 170 | 171 | 172 | 173 | ``` 174 | 175 | -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.3_网络编程框架/1.Flask Web开发/1_安装.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | --- 4 | 5 | 在大多数标准中,Flask都算是小型框架,小到可以称为微框架。Flask非常小,因此你一旦能够熟练使用它,很可能就能读懂它所有的源码。 6 | 7 | 但是,小并不意味着它比其他框架的功能少。Flask自开发伊始就被设计为可扩展的框架,它具有一个包含基本服务的强健核心,其他功能则可以通过扩展实现。你可以自己挑选所需要的扩展包,组成一个没有附加功能的精益组合,完全满足自身需求。 8 | 9 | Flask有3个主要依赖:路由、调试和Web服务网关接口(WSGI, Web server gateway interface)子系统由Werkzeug提供;模板系统由Jinja2提供;命令行集成由Click提供,这些依赖全都是Flask的开发者Armin Ronacher开发的。 10 | 11 | Flask原生不支持数据库访问、Web表单验证和用户身份验证等高级功能。这些功能以及其他大多数Web应用需要的核心服务都以扩展的形式实现,然后再与核心包集成。开发者可以任意挑选符合项目需求的扩展,甚至可以自行开发。这和大型框架的做法相反,大型框架往往已经替你做了大多数决定,难以使用替代方案。 12 | 13 | ## 克隆代码库 14 | 15 | `git clone https://github.com/miguelgrinberg/flasky.git` 16 | 17 | `cd flasky` 18 | 19 | `git checkout 1a` 20 | 21 | ## 虚拟环境 22 | 23 | 创建好应用目录之后,接下来安装Flask最便捷的方法是安装虚拟环境。虚拟环境是Python解释器的一个副本,在这个环境中你可以安装四邮报,而且不会影响系统中安装的全局Python解释器。 24 | 25 | 虚拟环境非常有用,可以避免你安装的Python版本和包与系统预装的发生冲突。为每个项目单独创建虚拟环境,可以保证应用智能范文所在的虚拟环境中的包,从而保持全局解释器的干净整洁,使其只作为创建更多虚拟环境的源。与直接使用系统全局的Python解释器相比,使用虚拟环境还有个好处,那就是不需要管理员权限。 26 | 27 | ## 创建虚拟环境 28 | 29 | 安装: 30 | 31 | `pip install virtualenvwrapper-win`这是Windows版本 32 | 33 | 创建虚拟环境: 34 | 35 | `mkvirtualenv 环境名` 36 | 37 | 进入虚拟环境: 38 | 39 | `workon 环境名` 40 | 41 | 退出虚拟环境 42 | 43 | `deactivate` 44 | 45 | 删除虚拟环境: 46 | 47 | `rmvirtualenv 环境名` 48 | 49 | 进入虚拟环境目录: 50 | 51 | `cdvirtualenv 环境名` 52 | 53 | ## 使用pip安装Python包 54 | 55 | Python包使用包管理器pip安装,所有虚拟环境中都有这个工具。与Python命令类似,在命令提示符会话中输入pip将调用当前激活的虚拟环境中的pip工具。 56 | 57 | `pip install flask` 58 | 59 | `pip freeze`查看虚拟环境中安装了哪些包 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /notes/第6章 网络编程/7.3_网络编程框架/1.Flask Web开发/2_应用的基本结构.md: -------------------------------------------------------------------------------- 1 | # 应用的基本结构 2 | 3 | --- 4 | 5 | ## 初始化 6 | 7 | 所以Flask应用都必须创建一个应用实例。Web服务器使用一种名为Web服务器网关接口(WSGI,Web server gateway interface)的协议,把接收自客户端的所有请求都转交给这个对象处理。应用实例时Flask类的对象,通常由下述代码创建: 8 | 9 | `from flask import Flask` 10 | 11 | `app = Flask(__name__)` 12 | 13 | Flask类的构造函数只有一个必须指定的参数,即应用主模块或包的名称。在大多数应用中,Python的__name__变量就是所需的值。 14 | 15 | ## 路由和视图函数 16 | 17 | 客户端把请求发送给Web服务器,Web服务器再把请求发送给Flask应用实例。应用实例需要知道对每个URL的请求要运行哪些代码,所以保存了一个URL到Python函数的映射关系。处理URL和函数之间关系的程序称为路由。 18 | 19 | ```python 20 | @app.route('/') 21 | def index(): 22 | return '

Hello World

' 23 | ``` 24 | 25 | 装饰器是Python语言的标准特性,惯常用法是把函数注册为事件处理程序,在特定事件发生时调用。 26 | 27 | index()这样处理入站请求的函数称为视图函数。如果应用部署在域名为`www.example.com`的服务器上,在浏览器中访问`http://www.example.com`后,会触发服务器执行index()函数。这个函数的返回值称为响应,是客户端结束到的内容。如果客户端是Web浏览器,响应就是显示给用户查看的文档。视图函数返回的响应可以是包含HTML的简单字符串,也可以是后文将介绍的复杂表单。 28 | 29 | ## 一个完整的应用 30 | 31 | ```python 32 | from flask import Flask 33 | app = Flask(__name__) 34 | 35 | @app.route('/') 36 | def index(): 37 | return '

Hello World

' 38 | ``` 39 | 40 | ## 动态路由 41 | 42 | ```python 43 | from flask import Flask 44 | app = Flask(__name__) 45 | 46 | @app.route('/') 47 | def index(): 48 | return '

Hello World

' 49 | 50 | @app.route('/user/') 51 | def user(name): 52 | return '

Hello, {}

'.format(name) 53 | ``` 54 | 55 | ## 调试模式 56 | 57 | Flask应用可以在调试模式中运行。在这个模式下,开发服务器默认会加载两个便利的工具:重载器和调试器。 58 | 59 | 启用重载器后,Flask会监视项目中的所有源代码文件,发现变动时自动重启服务器。在开发过程中运行启动重载器的服务器特别方便,因为每次修改并保存原代码文件后,服务器都会自动重启,让改动生效。掉使其是基于Web的工具,当引用抛出来未处理的异常时,它会出现在浏览器中。此时,Web浏览器变成一个交互式栈跟踪,你可以在里面审查源码,在调用栈的任何位置计算表达式。 60 | 61 | `app.run(debug=True)` 62 | 63 | ## 请求-响应循环 64 | 65 | ### 应用和请求上下文 66 | 67 | Flask从客户端收到请求时,要让视图函数能访问一些对象,这样才能处理请求。请求对象就是一个很好的例子,它封装了客户端发送的HTTP请求。 68 | 69 | 要想让视图函数能够访问请求对象,一种直截了当的方式是将其作为参数传入视图函数,不过这会导致应用中的每个视图函数都多出一个参数。除了访问请求对象,如果视图函数在处理请求时还要访问其他对象,情况会变得更糟。 70 | 71 | 为了避免大量可有可无的参数吧视图函数弄得一团糟,Flask使用上下文临时把某些对象变为全局可访问。 72 | 73 | ```python 74 | from flask import Flask, request 75 | app = Flask(__name__) 76 | 77 | @app.route('/') 78 | def index(): 79 | user_agent = request.headers.get('User-Agent') 80 | return '

Your browser is {}

'.format(user_agent) 81 | 82 | if __name__ == '__main__': 83 | app.run(debug=True) 84 | ``` 85 | 86 | -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/1.png -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/2.png -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/CSS布局常用属性.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/CSS布局常用属性.png -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/CSS文本常用属性.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/CSS文本常用属性.png -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/JavaScript数据类型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/JavaScript数据类型.png -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/OSI七层模型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/OSI七层模型.png -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/drink.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/drink.jpg -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/python.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/python.jpg -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/匈牙利命名风格.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/匈牙利命名风格.png -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/盒子示意图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/盒子示意图.png -------------------------------------------------------------------------------- /notes/第6章 网络编程/images/网络分层模型.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tq1258123/PythonNotes/7f57e47ac0d894e24e10a0a452fab0c11f0b0fd9/notes/第6章 网络编程/images/网络分层模型.jpg -------------------------------------------------------------------------------- /notes/第8章 Linux系统/Linux笔记.md: -------------------------------------------------------------------------------- 1 | # Linux笔记 2 | 3 | 4 | 5 | ## 计算机基础和`Linux`安装 6 | 7 | ### 计算机基础 8 | 9 | -------------------------------------------------------------------------------- /问题记录/学习过程中遇到的各种电脑问题.md: -------------------------------------------------------------------------------- 1 | # 学习中遇到的各种电脑问题 2 | 3 | 1. 安装`vmware`后,再安装虚拟系统出现蓝屏 4 | - 原因:由于我使用的电脑是`win 11`版本,而`vmware`版本较低,导致系统不支持`vmware`。 5 | - 解决办法:下载适合`win 11`版本的`vmware`。由于`vmware`卸载较难,下载软件中提供一键卸载软件。 6 | - 链接:https://pan.baidu.com/s/1pxOJW6wWC5ZRNBH4g431UQ 7 | 提取码:2cla 8 | 2. `pycharm`在运行代码是一直处于`console`状态 9 | - 原因:`python`文件名命名为特殊词语或关键字,导致报错 10 | - 解决办法:修改文件命名 --------------------------------------------------------------------------------