Python 认识与实践
Python
Python第一天
初识编码
- Python2默认英文编码 Ascii 英文,8位表示一个信息,2^8
1 | # -*- coding:utf-8 -*- |
- Unicode 万国码,32位表示一个东西,2^32
- Python3默认UTF-8 UTF-8 给Unicode压缩
文件编码
- 编写文件时,保存文件要用UTF-8格式,
- 以什么格式保存就用什么格式读取
- win10 中可以更改 cmd 编码
chcp 65001
解释器
1 | #!/usr/bin/env python |
运行:解释器 文件路径
在linux上右一种特殊的执行方法
- 给文件赋予一个可执行的权限
- ./a.py 自动去找文件的第一行 = /usr/bin/env/python a.py
输入
1 | print(你想要输出的东西) |
特殊:
- py2:print “你好”
- py3:print(“你好”)
数据类型
1 | 'alex' /"理解"/'''asds '''/""" ddsdd"""" ,一般称为字符创 |
- 字符串
- 单引号
- 双引号
- 三引号
- 整型
- 布尔类型
Python第二天
if ——else中有个pass
直接跳过否定
循环
1 | while True://可以加条件 |
for 和 while 的应用场景, 无穷使用 while
字符串格式化
%s 字符串
%d 数字
%% %
编码
- AsCII
- Unicode
- ecs2
- ecs4
- utf-8 中文用3字节
- utf-16
- gbk, 中文用2字节
- gbk-2312 中文用2字节
Git
右键 git bash here
初始化 git init(每一次都得做)
git add . 将当前目录下的文件都收集起来
git commit -m “第二天作业” 做记录 第几次收集
第一次执行的时候输入
- git config –global user.name “sssss”
- git config –global user.email “ www@qq,com”
- git config –global user.password “”
- git remote add origin 地址
代码提交并收集
- git status
- git add .
- git commit -m “记录”
- git push origin master 将本地目录同步到
修改代码或删除文件等对本地任何文件操作
- git statue
git add .
- git commit -m “记录”
git push origin master 将本地文件同步到码云仓库
下载 git 上的文件
1 | npm clone 地址 |
- and 取大 且
- or 取小 或 ,都为真,输出前,第二项有错输出错,第二项有真输出真
- not 非
- not>and>or
整型
- py2
- int超出范围自动转化为long (int)
- py3
- int
布尔类型(bool/boolen)
字符串(str/string)
字符变大小
1 | # value = "alex sb" |
确定字符串是否是数字
1 | num = input('请选择服务:') |
去除空格( rstrip / lstrip / strip(全去除))
1 | user = input("请输入用户名:") |
替换(replace)
1 | message = input("请说话:") |
切割 ( split / rsplit )
1 | message = "下开放,阿斯顿福建克拉斯,阿斯顿发流口水." |
公共的:
len() 计算长度
索引
1
2
3name = "sfdsa"
print(name[0])
print(name[-1]) #从右往左取值切片
1
2
3
4
5
6v = "sdfsadf"
s = v[2:3] # f
s = v[2:] # fsadf
s = v[:5] # sdfsa 从左往右取到第五个
s = v[:-1] # sdfsad 把 f 那掉了
print(s)- .extend() 会在内部循环自动添加到列表
列表
表示多个数据用列表
1 | user = ["sdsd","sdsdsd",99] |
公共功能
len
1
2
3users = ["aaa","aaa",99]
val = len(users)
print(val) #3索引
1
2
3users = ["aaa","aaa",99]
val = users[0]
print(val) #切片
1
2
3
4users = ["aaa","aaa",99]
val = users[0:2]
val = users[::2] # 输出为偶数索引的值
print(val) #删除
1
2
3
4
5
6
7
8users = ["hhhh","sdfsfa",99]
#方式一
users.pop(1)
print(users)
#方式二
del users[1]
print(users)注意:
- 字符串本身不支持修改删除【不可变的类型】
- 列表是可变类型
修改
1
2
3
4
5users = ["来来来","sdafssd","asdfsad"]
users[2] = 66
users[0] = 'sadfsa'
users[0][1]//选取是‘来’步长
1
2
3users = ["aaa","aaa",99]
val = users[0:2:2]
print(val) #for 循环
range(数字,数字,-1/ 1)-1 反过来,1 正过来
独有功能
append, 在列表的最后追加一个元素
insert(index,” “),在索引位置加元素
remove/pop,remove加元素删除,pop加索引删除,默认最后一个
clear,清空了
列表嵌套
1
2
3
4
5
6users = ["sadffsf",0,True,[asdfsa,asdfas,],[1sadf]]
users[0]
users[3] #[asdfsa,asfsa,]
users[3][-1] #"sadfsa"
users[]
元组转换列表
1 | va = list((111,22,33,44)) |
1 | enumerate(变量,序号) |
元组
元组书写规范
1 | users = [11,22,33,44] #列表 (可变) |
公共功能
- 索引 (排除:int/bool)
- 切片(排除:int/bool)
- 步长(排除:int/bool)
- 删除(排除:tuple/int/bool)
- 修改(排除:tuple/int/bool)
- for循环(排除:int/bool)
- len(排除:int/bool)
独有功能(无)
特殊:元组中的元素不可被修改/删除。
1 | v1 = (11,22,333) |
字典
请表示:刘伟达的信息,年龄18
1 | info = {"name":'sfd','age':'18','gender':'男' } |
基本格式
1 | data = [键:值,键:值] |
添加字典可以直接赋 键 和 值,也可以使用 setdefault(键,值) 方法
1 | dic.setdefault("k4","v4") |
.get() 方法找不到不报错,返回none
集合set
1 | v = {1,2,3,4,5,6} |
- 无序
- 无法索引删除
- 不重复的
集合的独有功能
- add 添加
- discard 删除
- update 更新往里面添加(批量添加)
- intersection 交集
- union 并集
- difference 差集
- symmetric_difference 对称差集
1 | v = set() #空集 |
注意:
1 | v = {1,2,'施钻','呵呵'} |
公共功能
- len
- for 循环
- 索引【无】
- 切片【无】
- 删除【无】
- 步长【无】
- 修改【无】
列表/字典/集合 -> 不能放在集合中 + 不能作为字典的 key(unhasable)
集合字典的查询速度 > 列表
深浅拷贝(面试)
深浅拷贝相等
文件操作
打开文件
1 | open('url',mode='方式',encoding='格式') |
文件的方式有:
单一的:
- r 只读不能写,文件必须存在
- w 只写不能读,写之前会清空,文件不存在会建立
- a 只追加不能读,不存在会新建,默认光标在最后
k可读可写:
- r+ 能读,写:根据光标位置操作写入(可能会覆盖)
seek
调整光标位置 - w+ 能读能写,写入清空文件,读取调整光标位置
- a+ 能读能写,因为追加,所以光标最后,读取一样调整
- r+ 能读,写:根据光标位置操作写入(可能会覆盖)
带b编码(二进制):
- rb
.encode('utf-8')
转换编码 - wb
- ab
- rb
三元运算(三木运算)
1 | v = 前面 if 条件 else 后面 |
1 | # 让用户输入值,如果值是整数,则转换成整数,否则赋值为None |
注意:先做出来,再简化
函数
面向对象的思想:函数式编程,(进行封装方法)
1 | # 函数的定义必须有 def |
参数赋值
1 | def foo(aa): #形参 |
返回值(return 1,2,3 返回元组)
1 | def func(arg): |
1 | # 1.让用户输入一段字符串,计算字符串中有多少大写A,将有多少个就这文件中写多少个’A’ |
总结
1 | # 情况1 |
参数
基本参数
任意类型
任意个数
1
2
3def fun(a1,a2,a3):
print(a1,a2,a3)
fun(1,'sda',True)
位置传参
1 | def fun(a1,a2): |
关键字传参(位置参数在前,关键在后)
1 | def fun(a1,a2): |
默认参数
1 | def fun(a,b=9) |
万能参数(打散),也可以与上面混用
*args(tuple)
- 可以接受任意个数的位置参数,并将参数转换成元组
有 *
无 *
- 可以接受任意个数的位置参数,并将参数转换成元组
1 | def func(*args): # 一般情况下写成 args |
**args(dict)
- 可以接受任意个数的关键字参数,并将参数转换为字典
有**
无**
- 只能关键字传参
综合应用
1 | def func(*args,**kwargs): |
调用函数
位置参数 > 关键字参数
用的较多:
- 定义函数:
- def func(a)
- def func(a,b=None) 对于默认值,如果是可变类型,—–>坑
- def func(*args,**kwargs)
作用域
全局作用域
局部作用域
一个函数就是一个作用域
作用域中查找数据规则:优先在自己的作用域找数据,自己没有就去“父级”-> “父级”->直到全局,没有就报错。
1 | def func(): |
- 子作用域中只能使用父级中的值,无法重新为父级的赋值
global 找到全局变量,可以修改
1 | name = '呵呵' |
nonlocal 找到上一级的修改
1 | name = '呵呵' |
注意:
全局变量大写,局部变量小写
函数小高级
函数赋值
1 | def func(): |
1 | def func(): |
函数可以当做变量来使用,加()返回值为none
1 | def fun(): |
1 | def fun(arg): |
面试题
1 | # 有10个函数, |
lambda 表达式(匿名函数)
用于表达简单的函数
1 | def func1(a1,a2): |
多种样子
1 | func1 = lambda : 100 |
列表的所有方法基本上返回都是NONE;字符串返回是个新值
内置函数
以前的都是内置函数
强制转换类
- dict()
- str()
- list()
- tuple()
- int()
- bool()
- set()
输入输出
- input
数学相关
abs() 绝对值
float() 转换成浮点型(小数值)
max() 最大
min() 最小
sum() 求和
pow()
1
2v = pow(2,3)
print(v) # 2**3round
1
round(1.2344,2) # 会四舍五入
divmod 两个数相除得 商 和 余数(单个接收会放在元组,两个不会)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34# 分页
# -*- encoding:utf-8 -*-
USER_LIST = []
for i in range(1,789):
v = {'name':'哈哈-%s' %i,'email':'123-%s@qq.com' %i}
USER_LIST.append(v)
# for item in USER_LIST:
# print(item)
# 数据总条数
total_count = len(USER_LIST)
# 每页显示10条
per_page_count = 10
# 总页码数
max_page_num,a = divmod(total_count,per_page_count)
if a > 0:
max_page_num += 1
pager = int(input("请输入查看第几页:"))
if pager < 1 or pager > max_page_num:
print("页码不合法,必须是 1 - %s" %max_page_num)
else:
"""
USER_LIST[0:10]
USER_LIST[10:20]
....
"""
start = (pager - 1) * per_page_count
end = pager * per_page_count
data = USER_LIST[start:end]
for item in data:
print(item)二进制十进制等之间相互转换
- bin, 只能将十进制转换为二进制
- oct , 将十进制进制转换为八进制
- int , 将其他进制转换成十进制
- hex 将其十进制进制转换成十六进制
1
2
3
4v1 = '' # 输入要转换的几进制数
v2 = int(v1,base=2) # 在2 的输入几进制数转换为十进制
print(v2)
# 其他进制转换为其他进制面试题
1
2
3
4# 一字节等于8位
# IP: 192.168.12.79 -> 四个字节 010001001.010001001.010001001.010001001
字符串拼接
'.'.join(字符串)
函数中高级(闭包/高阶函数)
函数内部执行不会混乱各自开辟了一个空间去执行
函数可以做返回值返回.
函数返回值问题注意:
1 | name = 'sd' |
闭包:
高阶函数
- 把函数当做参数传递
- 吧函数当做返回值传递
总结:
- 闭包概念:为函数创建一块区域并为其维护自己数据,以后执行时方便调用。【应用场景:装饰器/ SQLAlchemy源码】
内置函数(包涵面试的)
chr 将十进制数字转换为 Unicode 编码中的对应字符串
1
2v = chr(97)
print(v)ord 将字符串在 Unicode 编码中找到其对应的十进制
1
2
3v = "中国"
for item in v:
print(ord(item))应用:随机验证码
1
2
3
4
5
6
7
8
9
10import random
def get_random_code(length=6):
data = []
for i in range(length):
v = random.randint(65,90)
data.append(chr(v))
return ''.join(data)
code = get_random_code()
print(code)1
2import random # 导入一个模块
v = random.randint(起始,终止) # 生成随机数高级函数
map,循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到新列表中,并返回
1
2
3
4
5v1 = [11,22,33,44]
result = map(lambda x: x + 100,v1)
print(result) # [11,22,33,44,55,66] py2
print(list(result)) # 特殊 py3filter
1
2
3
4
5
6
7
8
9
10
11
12v1 = [11,22,33,44,'asds','asd']
# def func(x):
# if type(x) == int:
# return True
# return False
# result = filter(func,v1)
# print(list(result))
# result = filter(lambda x: True if type(x) == int else False,v1)
result = filter(lambda x: type(x) == int,v1)
print(list(result))reduce
1
2
3
4
5
6
7import functools
v1 = [1,2,3,4,5,6]
def func(x,y):
return x+y
# result = functools.reduce(func,v1)
result = functools.reduce(lambda x,y: x+y,v1)
print(result)
面试题
常用内置函数有哪些?
filter / map / reduce
什么是匿名函数?
1
2
3def func():
pass
v = [lambda x: x+100]
内置模块(.py文件)
将指定的 “字符串” 进行加密
1 | import hashlib |
加盐
1 | obj = hashlib.md5("asdfas".encode('utf-8')) |
密码不显示(只能在终端运行)
1 | import getpass |
id 与 is == 什么意思
函数的参数传递的是什么?【内存地址 = 引用 or 值】
总结
- 传参:位置参数 > 关键字参数
- 函数不调用,内部代码永远不执行
- 每次调用函数时,都会为此次调用开辟一块内存,内存可以保存自己以后想要用的值
- 韩式作用域,如果自己的作用域中没有,则往上级作用域找。
装饰器(6**)
1 | # 装饰器 |
总结
目的:不改变原函数的基础上,再函数执行前后自定义功能
编写装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 装饰器的编写
def x(func):
def y():
ret = func()
return ret
return y
# 装饰器的应用
def index():
pass
def manage():
pass应用场景:想要维函数扩展功能时,可以选择用装饰器。
记住:
装饰器编写格式
1
2
3
4def 外层函数(参数):
def 内层函数(*args,**kwargs):
return 参数(*args,**kwargs)
return 内层函数装饰器应用格式
1
2
3
4
def index():
pass
index()为什么加 *args, **kwargs ,防止要传参
推导式
列表推导式
基本格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# 变量 = [ for 循环变量 for 循环一个可迭代对象]
vals = [ i for i in 'alex']
v1 = [ i+100 for i in range(10)]
v2 = [ 99 if i>5 else 66 for i in range(10) ]
def func():
return 123
v3 = [ func for i in range(10)]
v5 = [ lambda : 100 for i in range(10)]
result = v5[9]()
v8 = [lambda x: x*i for i in range(10)] # 新浪面试题
# 1.请问 v8 是什么?
# 2.请问 v8[0](2) 的结果是什么?
# 面试题
def num():
return [lambda x:i*x for i in range(4)]
# num -> [函数,函数,函数,函数]
print([ m(2) for m in num() ]) #[6,6,6,6]
#################################################
v9 = [ i for i in range(10) if i>5]
集合推导式
1
v1 = { i for i in 'aelx'}
字典推导式
1
v1 = { 'k'+str(i):i for i in range(10)}
模块:
1 | import time |
带参数的装饰器
- 应用场景:flask框架 + Django缓存 + 面试题(写装饰器实现被装饰的函数要执行 N 次)
- 模块
- os
- sys
- time (三种类型)
- datetime
- timezone 时区
面试题:
- def func(a,b=[]) 有什么陷阱? 如果不传递参数,默认指向同一个地址,这个就是参数最好是不可变类型
- 看代码写结果
递归
1 | def func(): |
默认递归次数限制 1000
带参数的装饰器
1 | def x(counter): |
欠
- 元数据:flask 框架
- 多个装饰器:Flask 框架
1 |
|
总结:
- 基本装饰器
- 带参数的装饰器
模块
sys模块
python 解释器相关的数据。
sys.argv
1
2
3
4
5
6
7
8
9
10
11
12
13# -*- encoding:utf-8 -*-
"""
删除文件的脚本
让用户执行脚本传入要删除的路径,在内部帮助将木目录删除
"""
import sys
# 获取用户执行脚本时,传入的参数
path = sys.argv[1]
# ['D:/ggy/Desktop/Python/课堂练习/day13/模块传参.py'] 在目录后面加删除文件名
# 删除
import shutil
shutil.rmtree(path)sys.path 当前项目的执行路径,可以添加才保住模块运行
os模块
和操作系统相关的数据
os.path.exists(path) 如果 path 存在,返回 True,如果 path 不存在,返回 False
os.stat(“文件名”).st_size 获取文件大小
os.path.abspath() 获取绝对路径
os.path.join 路径拼接
os.path.dirname() 获取上级目录
1
2v1 = r"D:\ggy\Desktop\Python\课堂练习\day13\模块传参.py"
os.path.dirname(v1)- 补充:
- 转义:r 就是\
- 补充:
os.listdir()
1
2
3
4
5import os
result = os.listdir(r'D:\ggy\Desktop\Python\课堂练习\day13')
print(result)
# 只有当前目录下的所有文件os.walk()
1
2
3
4
5
6
7
8
9
10import os
result = os.walk(r'D:\ggy\Desktop\Python\课堂练习\day13')
for a,b,c in reult:
print(a,b,c)
"""
for item in c:
path = os.path.join(a,item)
print(path)
break
"""shutil
1
2
3# 删除
import shutil
shutil.rmtree(path)sys.exit()
py2:
- xrange ,不会在内存中立即创建,而是在循环时。边循环边创建
- range ,在内存立即把所有的值都创建
py3:
range, 不会在内存中立即创建,而是在循环时。边循环边创建
list(range) ,
内置模块,python内部提供的功能
第三方模块,下载 / 安装 / 使用。
1
python3 -m pip install xlrd
同时存在两个python版本就用这个方法,记得添加环境变量
自定义模块
1
2
3
4
5
6
7
8
9
10# 创建 xxx.py 文件
def f1():
pass
def f2():
pass
# x1.py
import xxx
xxx.f1()
xxx.f2()
内置模块
- os.makedir , 创建目录
- os.makedirs , 创建目录和子目录
- sys.path , 默认python 去导入模块时,会按照 sys.path 的路径找模块
json模块
json 是一个特殊的字符串。【长的像列表 / 字典 / 字符串 / 数字 / 真假】set 不支持和 tuple转换为 list
转换成 json 叫序列化,反过来叫 反序列化
1 | import json |
- 模块基础知识
- time / datetime
- json / picle
- shutil
- logging
- 其他
模块(类库)
内置模块
第三方
- json / time /os/sys
自定义
模块可以是 py 文件也可以是文件夹
py2中必须写 _ _int_ _.py
文件就是包,py3可以没有,最好加上
定义模块可以把文件或者一个文件夹(包)当做一个文件夹,方便以后其他使用
导入模块先加载模块并执行
1 | # 第一种加载 |
导入包
1 | # 第一种 |
总结
模块和要执行的同一文件 且 需要 模块中的很多功能时,,推荐同:import 模块
其他推荐: from 模块 import 模块 模块。函数(0
其他推荐: from 模块。模块 import 函数 函数()
json
- 字典或者列表中有中文,序列化时想要保留中文显示
- dumps(,ensure_ascii=False)
- dump(写入文件,文件操作)
- loads 读到文件
- 优点:所有语言统一缺点:只能序列化基本数据类型
- 不加s 文件操作
pickle 序列化
- 优点:python中所有东西都能被她序列化(socket对象):
- 缺点:序列化内容只有python认识
shutil 模块
删除
重命名
time 模块
- time.time()
datetime模块
异常处理
1 | try: |
迭代器
自己不会写只会用。
迭代器,帮助你对某种对象中的元素进行逐一获取
迭代器内部都有一个 next 方法 ,用以一个个获取数据。
生成器
1 | def func(arg): |
生成器推导式
1 | v2 = (i for i in range(10)) # 生成器推导式,创建了一个生成器,内部循环执行。 |
装饰器
相对导入,层级越深,丶越多
1 | from .. import utils |
主文件
1 | __name__ |
面向对象
1 | class Bug: |
初始化方法,构造方法
继承
1 | # 父类(基类) |
什么时候用到继承?
多个类中有公共方法时,可以继承
1 | class Base |
继承关系中的查找顺序:
注意
- self 是谁?self 参数时python帮助我们自动传递
- self 是哪个类创建的,就从此类开始找,自己没有找父类
多继承
多态(多种类型/多种形态)鸭子模型
1 |
什么是鸭子模型,传参时无须指定模型
1 | 对于一个函数而言 |
成员
变量(字段)变量修饰符
1 | # -*- encoding:utf-8 -*- |
方法 方法修饰符
1 | # -*- encoding:utf-8 -*- |
面试题:静态方法/类方法和实例方法的区别?
从创建方式:
静态方法需要加@staticmethod,类方法则添加@classmethod,实例方法无须
从调用角度:
实例方法需要创建对象来调用,静态方法和类方法则需要类来调用
从应用场景来说;
如果在方法内部不会用到对象数据时,则可以设置称为静态方法或者类方法
如果你在方法中用到当前类,则设置成为的类方法
嵌套 / 组合(建模)
1 | """ |
组合补充
主动调用其他类的成员
1 | # 方式一 |
特殊成员(这是语法)
__init__
初始化的,不是构造方法- 对象()自动执行
__call__
- 对象【】自动执行
__getitem__
- 对象【‘ss’】= 11 自动执行
__setitme__
无返回值 - del 对象【xx】 自动执行
__delitem
无返回值 - 对象 + 对象 自动执行
__add__
- with 对象 自动执行 进来
__enter__
返回值 出去__exit__
- 真正的构造方法
__new__
在 init 之前先执行,创建一个空的对象,为对象初始化 - 把封装的值以字典形式显示
__dict__
- 迭代器
isinstance / issubclass / type
区分方法和函数
内:方法
外:函数
反射
handler()判断对象是否存在于模块中
getattr(模块,函数)根据字符串为参数,去模块 / 类 / 对象(一切皆对象) 中寻找与之同名的成员
其他
约束
类的约束
1 | def func(arg): |
抽象类和抽象方法
1 | form abc import ABCMeta,abstractmethod |
什么是接口以及作用?
接口是一种数据类型,主要约束派生类中必须实现指定的方法
python 中不存在,Java和c#中有
约束方法
- 抽象类和抽象方法,编写上麻烦
- 人为主动抛出异常
约束时,抛出异常是否可以用其他的
不专业:
raise Exception()
专业:
raise NotImplementedErrod()
应用场景:
多个类,内部必须有某些方法,需要使用基类 + 异常进行处理
自定义异常
logging
osi 7层模型
网络之间的数据传输,
7层模型
- 应用层 使用软件
- 表示层 看到数据,如视频。图片
- 会话层 保持登陆或者链接状态
- 传输层 TCP/UDP
- 网络层 IP
- 数据链路层 MAC
- 物理层 将数据转换成电信号
5层模型
- 应用层
- 应用层
- 表示层
- 会话层
- 传输层
- 网路层
- 数据链路层
- 物理层
4层模型
- 应用层
- 应用层
- 表示层
- 会话层
- 传输层
- 网络层
- 物理层
- 数据链路层
- 物理层
TCP 三次握手四次挥手
socket 客户端向入伍端发送请求时:三次握手
客户端和服务端断开连接:四次挥手
并发和并行
并发,伪 由于执行速度特别快,人感觉不到停顿
并行,真 创建10个人同时擦欧总
线程。进程
单进程,单线程的应用程序
python调用系统的多线程和多继承
python中只能创建单进程和单线程
多线程在一个进程执行时会分时执行
GIL锁
1 | import time |
python 线程编写
主线程默认等子线程
为什么创建线程
由于线程时 cpu 工作的最小单元,创建线程可以利用多核优势实现并行操作
为什么创建进程?
进程与进程之间做数据隔离(Java/c#)
io 请求不占用 cpu
线程池(py3 独有)
线程安全
线程安全,多线程操作时,内部会让所有线程拍碎处理
线程不安全 + 人 => 排队处理
进程
数据共享
锁
进程池
爬虫实例(模块)
- requests
- bs4(beautifulsoup)
进程锁
当用到同一个数据时,要加锁,数据共享
与线程锁一样操作
进程池 py3 中
初识爬虫
pip install requests
pip install beautifulsoup4
优先使用线程好
IO多路复用
基于IO复用 + socket 实现并发请求
作用:检测多个 socket 是否已经发生变化(是否已经连接成功 / 是否已经获取数据)(可读 / 可写)
基于 IO 多路复用 + socket 实现并发请求(一个线程100个请求)
IO 多路复用
socket 非阻塞
基于事件循环实现的异步非阻塞框架
已经实现的模块:Twisted 爬虫时
作用
检测多个 socket 是否发生变化
系统中有 select(1024个socket ,循环去检测) 、 poll(不限制个数、循环检测(水平触发)) 、epoll(不限制,回调方式(边缘触发))、三种模式
python 模块:
select.select
select.epoll
提高并发方案
- 多线程
- 多进程
- 异步非阻塞模块(Twisted) scrapy 框架 (单线程完成并发)
协程
协程,操作系统中不存在的东西,由程序员创造出来的
可以认为:微线程,对一个线程进行分片,使得线程在代码块之间进行来回切换执行,而不是在原来逐行执行。
安装一个模块:
1 | pip instanll greenlet |
单纯的协程无用
协程的存在
协程 + IO操作
安装 gevent 内部依赖 greenlet 加 IO 切换
1 | pip install gevent |
协程可以提高并发吗?
协程自己本身无法实现并发(甚至性能会降低)
协程 + IO切换性能提高
面试必备:
进程,线程,协程的区别?
列表生成式 也式一种生成器
asyncio 模块
创建协程函数使用asyncio.coroutine 装饰器
- tensorflow机器学习
三种异步方式
多线程
多进程
协程
异步不一定就是多线程和多进程
python -m http.server
单例模式
生成单例模式
singleton pattern 软件设计模式
一个类只有一个实例对象
实现单例模式的方式:
- 使用模块
- 使用
__new__
- 使用装饰器(decorator)
- 使用元类(metaclass)
1 | class Singleton(object): |