一个前端转python速通学习之路(长篇)
由于公司python离职,必须兼顾python项目的维护,于是恶补了python,写出一份速通攻略,以提供前端想学习python的朋友,此文字默认跳过安装pycharm和python环境,不对的地方欢迎指出
基础篇
一、数据类型
六种:
数字(Number) | 整数(int)浮点数(float) 复数(complex)布尔(bool) | 复数:4+3j布尔:底层true是1 ,false是0定义布尔首字母要大写 True |
---|---|---|
字符串(String) | ||
列表(List) | 有序可变序列 (数组) | |
元组(Tuple) | 有序不可变序列(元组) | |
集合(Set) | 无序不可重复 | |
字典(Dictionary) | 无序key-value集合 |
1.1. 查看数据类型
- type()
name = "张三"
print(type(name))
# <class str>
1.2. 类型转换 str() int() float()
- 转字符串 str()
任何类型都可以转字符串
str=(11)
- 转整数-数字 int()
需要确保字符串内容全是数字
浮点转整数-去除小数部分
- 转浮点数-数字 float()
整数浮点 补充.0 如11 =>11.0
1.3. 定义数据类型
使用:定义数据类型 或者 用注释#type:
var_1:int=10 #使用:定义 同于ts
var_2=10 # type:int
二.运算符
1.算数运算符
- // 取整除
- % 取余数
- ** 求平方
2.赋值运算符
-+ 、-=、 *=、 /=、 %= 、**= 、//=
三.变量
1.1. 命名规范
- 大小写敏感,如变量可以作为两个变量 如:a 和 A
- 不能用关键字 如:False True None And... 必须要大小写一样
1.2. 函数内部 定义全局变量 global
def getName(){
global name="张三"
}
#需要修改外部的全局变量 需要再函数内部 用global
四、字符串
1.字符串
可以单引号、双引号、三引号(注释)
引号嵌套:字符串要包含引号可以使用\转义
a='123'
b="123"
c='''
123
123
'''
2.字符串拼接
- 方法一:+进行拼接
- 方法二:%s %变量,如果单个占位 列:“我的名字叫%s”%name,如过多个占位,保持顺序,用括号:“我的名字叫%s,我的年龄%s岁”%(name,age)
- 方法三:字符串前面f 变量用{},类似模板语法 例如: f"我是{name},我今年{age}"
占位符详解:
%s | 将内容转换为字符串,放入占位位置 |
---|---|
%d | 将内容转换为整数,放入占位位置, |
%5d | 表示将整数的宽度控制在5位,如果不足用空格补充,如果限制数字位数小于原数字 那么不会生效 |
%f | 将内容转换为浮点型,放入占位位置 |
%5.2d | 表示将整数的宽度控制在5位,小数精度为2,如果不足用空格补充 |
%.2d | 只限制小数 |
format
#方式1
"{} {}".format("hello", "world")
'hello world'
#方式2
"{1} {0} {1}".format("hello", "world")
'world hello world'
五、字符串方法
1.字符串原字符串无法修改 只能得到新字符串
2.str.index(元素) 查找元素下标
name="张山李四"
name.index("李四")#2
#返回:命中的第一个下标 没有命中报错
3.str.replace(被替换元素,新元素,最大替换次数) 替换
name="张山李四"
#最大替换次数,如不设置 则全部替换
str=name.replace("张三","李四")
#返回:李四李四
4.str.split(元素) 切分 等同js
name="张山和李四"
arr=name.split("和")
#解析:以 和 切割数组
#返回:[张三,李四]
5.str.strip() 去除空格或者指定元素 rstrip()去掉右边 ltrip()去掉左边
name=" 张山和李四 "
#不传入参数
name.strip() #去除首位空格
#返回:"张山和李四"
#传入参数 去除两边字符 没办法除去中间
str="12ASSDF21"
str.strip("12")
#解析:不按照参数顺序 12或者21都要去除
#返回"ASSDF"
6.str.count() 统计某元素出现的次数
name=" 张山和李四和 "
name.count("和") #2
7.len() 统计字符串长度
name=" 张山和李四和"
len(name) #6
8.find() 查找字符串是否出现
str='123'
str.find("4") #-1
#是-返回第一次出现的下标 不是-返回-1
9.caitalize() 首字母大写
str='hello'
str.caitalize() #Hello
10.isdigit() 是否只包含纯数字字符
num="123"
num.isdigit()#true
11.islower() 是否全部包含小写字符
s="heelo"
s.islower()#true
12.lower() 全部变成小写 upper()全部变成大写
s="Hello"
s.lower()#hello
s.upper()#HELLO
13.startwith() 是否以某个字符开头 endwith()是否以指定字符结尾
s="hello"
s.startwith("h")#true
s.endwith("o")#true
14.* 重复生成多个
a="b"
print(a*3)#bbb
六、range
1.一个参数 rang(num)
rang(10)
表示[0,1,2,xxxx,9]
2.两个参数 rang(num1,num2)
rang**(5,10)
表示[5,6,7,8,9] 包头不包尾
3.三个参数 rang(num1,num2,step)
rang(5,10,2)
第三个参数 数字间隔2 (步长)。 5,7,9
七、函数
1.关键字 def 定义函数
def 函数名(参数):
#函数体
retrun 返回值
2.无返回值函数 内容为None 类型为NoneType
3.多个返回值
def fn():
retrun 1,2 #变量用,隔开
x,y=fn() #多个值接受
# x为1 y为2
4.不固定参数 *args和**kwargs
# 方法一:位置不定长
def fn(*args):
print(args)
fn("tom",15)
# ("tom",15) 得到元组类型
# 方法二: 关键字不定长
def fn(**kwargs): # 参数必须是key=vale
print(kwargs)
fn(name='张三')
# {name='张三'} 得到字典类型
5.匿名函数 lambda
lambda 传入参数:函数体(一行代码)
lambda x,y:x+y
6.函数类型定义
def add(x:int,y:int)->int:
return x + y
#参数同ts
#->类型 定义返回值
八、列表
1.下标可以是 负数
九、列表方法
1.arr.index(元素) 查询下标
arr=[1,2,3,4]
arr.index("1")
#解析:元素存在返回下标,不存在 抛出异常
#返回:0
2.arr.insert(下标,元素) 指定位置插入元素
arr=[1,2,3,4]
arr.insert(0,"5")
#解析:插入 第一个参数下标 第二个参数元素
#改变后arr为 [5,1,2,3,4]
3.arr.append(元素) 末尾插入
arr=[1,2,3,4]
arr.append(5)
#解析:尾部插入 相当于push
#改变后arr为[1,2,3,4,5]
4.arr.extend(其他列表) 末尾合并
arr=[1,2,3,4]
arr1=[5,6]
arr.extend(arr1)
#解析:拼接数组 相当于concat
#改变后arr为[1,2,3,4,5,6]
#----------------改变原数组
5.del arr[下标] 删除元素方法
arr=[1,2,3]
del arr[0]
#解析:删除指定下标数据
#改变后arr为[1,2]
5.arr.pop(下标) 删除元素方法-返回删除元素
arr=[1,2,3]
arr.pop(0)
#解析:删除下标为0的元素 返回删除具体元素
#返回:1
#改变后arr为[2,3]
6.arr.remove(元素) 删除指定元素方法
arr=[1,2,3,1]
arr.remove(1)
#解析:删除指定匹配的第一个元素
#改变后arr为[2,3,1]
7.arr.clear() 清空数组
arr=[1,2,3,1]
arr.clear()
#解析:清空数组
#改变后arr为[]
8.arr.count(元素) 统计列表内某元素的数量
arr=[1,2,3,1]
conut=arr.count(1)
#解析:统计列表内1的数量 只能统计第一层 二维数组里 无法统计
#返回:2
9.len(arr) 统计数组长度
arr=[1,2,3,1]
conut=len(arr)
#解析:获取数组长度
10. sorted() 排序
#语法:sorted(容器,reverse) reverse表示正序或者反序 不传默认正序
list=[3,2,5,1]
sorted(list)
#[1,2,3,4,5]
10. sort() 可用于复杂结构排序
#语法:sort(key=选择排序依据函数,reverse=True|Flase)
my_list = [["a",33],["b",55],["c",11]]
#定义排序方法
def choose_sort_key(element):
return element[1] # 相当于安装每个元素的下标1排序
my_list.sort(key=choose_sort_key, reverse=True)
print(my_list)
#或者匿名函数
my_list.sort(key=lambda element: element[1], reverse=True)
11.+ 合并两个列表
a=[1,2]
b=[3,4]
c=a+b #[1,2,3,4]
#----------------得到新数组不会改变原数组
12.* 快速生成重复数组
arr=[1,2]
print(arr*3) #[1,2,1,2,1,2] 重复三次
13.in 方法 判断数据是否在数组中
a=[1,2,3]
print(1 in a) #判断1是不是在a数组中 返回true 和false
14.max()最大值,min()最小值
#只适合于纯数字的列表
a=[1,2,3]
print(max(a)) #3
print(min(a)) #1
15.reverse 反序数组
a=["Z","N","2","1"]
a.reverse()
print(a)#["1","2","N","Z"]
十、元组及其方法
1.定义-通过括号或者关键之tuple
t1=(1,"hello",True)
t2=()
t3=tuple()
#------------如果是单独的元素必须加上逗号 不然不会认定为元组
t4=(1,)
2.元组方法
元组不支持修改 目前支持三个方法 find、count、len() 或者切片
arr=(1,"hello")
arr.find("hello") #1
arr.count("hello") #1
print(arr[0:1])#(1,"hello") 切片
len(arr) #2
3.不支持修改(增加和删除)
如果元组嵌套列表,列表里面的值可以修改
十一、切片
1.序列
序列才能切片,不会修改原数据
序列:内容连续、有序、可使用下标索引的容器
列表、元组、字符串都可以视为序列
2.切片 序列[起始下标:结束下标:步长]
序列[起始下标:结束下标:步长]
三个参数:
起始下标:可省略 从头开始
结束下标:可省略 结尾结束 包头不包尾
步长:可以为负数 从数组倒序开始 默认步长为1 可省略
list=[0,1,2,3,4,5]
r=list[1:4] #123
r1=list[:] #[0,1,2,3,4,5]
r2=list[::2] #[0,2,4]
#步长为复数 开始结束省略
str="01234567"
#步长为复数
r3=str[::-1] #76543210
r4=str[::-2] #7531
#步长为复数 开始结束有值
r5=str[3:1:-1] #32
十二、集合
1.定义
1.用{}定义 set={"张三","李四","王五"}
2.用set() my_set=set() #定义空集合
#重点:集合无下标, 只有不可变的数据类型才能加入集合
2.添加add
python
set={"张三","李四","王五"}
set.add("HELLO") #{"张三","李四","王五","HELLO"}
3.删除remove
set={"张三","李四","王五"}
set.remove("王五")#{"张三","李四"}
4.随机取出元素 pop
set={"张三","李四","王五"}
ele=set.pop()
#取出元素后 改变原有的set 有返回值 ele就是随机取出的数
4.清空clear
set={"张三","李四","王五"}
set.clear()
#该集合被清空 {}
5.差级difference 或者 减法 -
set1={1,2,3}
set2={1,5,6}
set3=set1.difference(set2)
#解析:以set1为标准获得set2的差级
#set3为{2,3} 原有的集合不变
6.消除两个集合相同的 difference_update()
set1={1,2,3}
set2={1,5,6}
set1.difference_update(set2)
#相处set1相比set2相同的
#此时set1 为{2,3}
#set2不会发生变化
7.合并 unior
set1={1,2,3}
set2={1,5,6}
set3=set1.unior(set2)
#合并set1和set2
#set3为{1,2,3,5,6}
#set1和set2不会发生改变
8.统计集合数量 len()
set1={1,2,3}
l=len(set1)#3
9. 并集 | 交集&
a={1,2,3}
b={3,4,5}
print(a|b) #{1,2,3,4,5}
print(a&b) #{3}
十三、字典
1.定义
使用{}或dict() 例:dict=dict()
存储元素为:键值对,例:{key:value,key:value}
2.取值
dict={"张三":12}
#方法一:
dict["张三"]
#如果不存在的属性 会异常
#方法二:
dict.get("李四") #没有不会异常 返回None
3.删除pop
dict={"张三":12,"李四":14}
val=dict.pop("张三")
#参数为键名
#返回被删除的元素 原字典{"李四":14}
#此时 dict为{"李四":14}
val=dict.pop("w","not exist")
#删除的键不存在会异常 第二个参数会默认给返回值不会异常
#此时 val 为not exist
4.清空clear
dict={"张三":12,"李四":14}
dict.clear()
5.获取全部键 keys() 获取全部值 values()
dict={"张三":12,"李四":14}
for key in dict.keys()
print(key) #张三 李四
for value in dict.values()
print(value) #12 14
6.获取长度 len()
7.拷贝 copy()
d1={name:'1'}
d2=d1.copy()
#只能拷贝第一层
8.列表快速转换字典 dict.fromkeys()
list=["name","age","address"]
d3=dict.fromkeys(list,'Null') #第一个参数为列表 第二个参数为列表的值
#d3 = {"name":"Null","age":"Null","address":"Null"}
9.in 判断是否在字典中
dict={"张三":12}
print("张三" in dict) #true
10.setdefault 和get类似 不存在会添加
dict={"张三":12}
dict.setdefault("李四",13)#返回13
#如果key存在返回 对应的value
#如果不存在 就改变原字典 新增key 如果存在第二个参数有的话值 value为第二个参数
#没有第二个参数 value 默认为None
11.update 更新(合并)
dict={"张三":12}
dict1={"张三":13,"李四":14}
dict.update(dict2)
#dict 此时为{"张三":13,"李四":14}
#原有的键和新的一样那么会更新新的 没有的会添加
12.删除popitem()
dict={"张三":12,"李四":14}
dict.popitem() #随机删除一个键值对
十四、内置函数
1.len()
获取长度
2.max()
最大元素
3.min()
最小
4.类型转换
- list()
- str()
- tuple()
- set()
参数为容器
5.dir()
大致理解为:查看对象属性和方法
dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;
带参数时,返回参数的属性、方法列表
6.isinstance()
#判断一个对象是否是一个已知的类型(是不是实例)
a = 2
isinstance (a,int)#True
isinstance() 与 type() 区别:
- type() 不会认为子类是一种父类类型,不考虑继承关系。
- isinstance() 会认为子类是一种父类类型,考虑继承关系。
7.print()多参数
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
#objects -- 复数,表示可以一次输出多个对象。输出多个对象时,需要用 , 分隔。
#sep -- 用来间隔多个对象,默认值是一个空格。
#end -- 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符串。
#file -- 要写入的文件对象。
#flush -- 输出是否被缓存通常决定于 file,但如果 flush 关键字参数为 True,流会被强制刷新。
十五、文件
1.打开文件open(name,mode,encoding) 和with open((name,mode,encoding) as f
1.1 open
# open(name,mode,encoding) # encoding不是第三顺位 传参需要指定encoding指定
# name:打开文件名或者具体路径
# mode:设置模式 只读、写入、追加
# r 只读
# r+ 读写 不会主动生成文件
# w 写入 原有内容会被删除 如果该文件不存在会创建新文件 从头写
# a 表示追加 新内容会在已有内容后 如果不存在会创建新文件 从尾写
# 上面模式加b就是以二进制模式 例如 wb 以二进制写入
# encoding:编码格式 例utf-8
#例: f=open("python.text","r",encodeing="UTF-8")
1.2 with open((name,mode,encoding) as f 通过语法可以自动关闭文件
with.open("python.text","r",encodeing="UTF-8") as f
# f为文件对象名字
2.文件对象方法
2.1读取
1.文件对象.read(num) # 读取文件内容 num 表示读取字节数 比如10个字节 不传默认全部
如果连续调用两次 下一个会从上一个内容后继续读取
2.文件对象.readLines() #按行读取 读取成菜单 会读出\n 读取全部文字 返回一个列表
也会继承上次read读取内容 下一个会从上一个内容后继续读取
3.文件对象.readLine() #只读取一行 多次调用读取多行
######.可以使用for 读取 也会收到read影响
2.2关闭
文件对象.close()
解除占用
2.3写入
文件对象.write("hello")
写入到内存,一般保存图片之类的
文件对象.writelines(参数)
接受一个可迭代对象 比如列表或元组 需要换行必须在每个元素后加入\n
对象.flush()
刷新 保存
3.文件指针
#tell() 获取当前指针位置
文件对象.tell()
#seek() 移动指针
文件对象.seek(参数1,参数2)
#参数1 偏移量
#参数2 偏离相对位置 0是开头 1是相对当前位置唯一 2是末尾 如果以文本模式打开 只能取0 二进制无所谓
十六、异常
1.语法
try:
# 代码
except:
# 异常处理
else:
#没有异常
finally:
#有或者没有 都要执行
2.捕获指定异常
try:
# 代码
except NameError as e:
#except [异常名 as 别名]:
# 异常处理
# NameError 为指定异常 as e设置异常对象别名为e
#多个异常可以用(NameError,ZeroDivisonError) 括号包裹 逗号隔开
#捕获多个异常 可以用 Exception 或者直接except:
3.手动抛出异常 raise
#方法一
raise #无参数 引发当前上下文捕获的异常 例 如果在except中就抛出当前异常 不在的或默认RuntimeError
#方法二
raise 异常名 #引发指定异常
#方法二
raise 异常名(描述信息) #引发指定异常 同时附带描述信息
4.自定义异常
class AuctionException(Exception): #必须继承Exception父类 自定义异常名字类
pass #pass关键字占位
#使用
raise AuctionException("自定义错误内容")
try:
XXXX
except AuctionException as e
print(e) #自定义错误内容
十七、模块
1.导入
[from 模块名] import [模块 | 类 | 变量 | 函数 |][as 别名]
常用:
import 模块名
from 模块名 import 类、变量、方法
from 模块名 import *
import 模块名 as 别名
from 模块名 import 功能名 as 别名
例如:
import time
time.sleep(5)
from time import *
sleep(5)
2.自定义模块
import 自定义文件名
如果在自定义模块里 有调用函数方法 导入会直接调用
如果非要写 但是不想调用 用__main__
例: if name=="main": __name__是python内置变量 右键调试会把name变成main
fn()
自定义模块指定导出 限制于 import *
all=["fn"]
def fn():
XXX
def fn1():
XXX
此时 如果用*导入那么只能用fn 不能用fn1
3.内置常用模块
math模块
import math
math.ceil(x) #返回大于等于x的最小整数 向上取整
math.floor(x) #返回小于等于x的最小整数 向下取整
math.fabs(x) #取绝对值 返回一个浮点数
math.fsum([1,2,3])# 对数组内的数字 求和 返回浮点数
math.pow(x,y) #求幂 x的y次方
math.sqrt(x) #开方 返回浮点数
random模块
import random
random.random() #返回一个0到1的随机数 能取0取不到1 [0,1)
random.randint(a,b) #生成一个a和b之间的随机整数 包含a,b [a,b]
random.randrange(a,b) #生成一个a和b之间的随机整数 包含a, 不包含b [a,b)
random.uniform(a,b) #生成一个a和b之间的随机浮点数 包含a,b [a,b]
random.choic([]) #从列表里生成一个数
random.shuffle([]) #打乱列表的顺序 无返回值改变原址
random.sample([],n) #随机从列表里取出 n个数字 返回一个数组
十八、包
1.创建包
- 右键目录 创建 Python Package
- 取包名 会自动创建__init__.py 文件(不写东西都行,必须存在 代表包 方便引入模块)
- 在同级目录可以取模块名
- 如果要使用__all__就在__init__.py 文件里写
- 导入 直接包就可以 不需要单独操作模块
2.导入
import 包名.模块名字
from 包名 import 模块名字
from 包名.模块名字 import 方法
3.第三方包
1.安装
方法1:
# pip install 包名 (等同于npm 安装python自带)
#国内镜像
#pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名
方法2:
1.编辑器右下角 python版本号 点击
2.interpreter settings 点击
3.当前有包的列表 点击左上角加号
4.搜索 点击下 install package
5.右侧的Options 里可以加入镜像网址pypi.tuna.tsinghua.edu.cn/simple
十九、第三方库
1. json
转换为json格式:
import json
data=[{"name":"张三"}]
str=json.dumps(data,ensure_ascii=False) # ensure_ascii表示不使用编码 直接转
json转换原有格式:
import json
data='[{"name":"张三"}]'
l=json.loads(data)
2. PyEcharts
2.1. 折线图
from pyecharts.charts import Line
Tine = Line()
Tine.add_xaxis(["中国"])
line.add_yaxis ("GDp",[30,20,10])
Tine. render()
#右键运行后 同级会生成一个render.html文件 进入文件编辑器右上角自带预览
3. pymysql
操作mysq数据库
python3.0使用pymysql
python2.0使用mysqldb
import pymysql
#连接数据库
def connect_db():
db=pymysql.connect(host="localhost",user="root",password="",charset="utf-8")
cursor=db.cursor() # 返回操作数据库对象
cursor.execute("select version()")#执行sql语句 此例子为:查询数据库版本
data=cursor.fetchone()#查询结果 数据库版本号
db.close()#关闭
二十、类
1.定义
class Student
name=None
def say(self,参数2):
#要访问成员属性 需要self.name self代表自己
#参数2为形参
stu_1=Student()
stu_1.name="张三"
#和js不同的是不需要new关键字
2.封装
定义私有变量或方 使用__定义
class Student
__name=None #私有变量
def __say(self): #私有方法
print()
#在类的内部可以使用 私有变量 实例访问不了
3.继承
1.如果子类没有定义自己的初始方法,则父类的初始方法自动会被调用,但是如果要实例化子类必须传入父类初始化方法的参数
2.如果在子类定义初始化方法,没有显示调用:父类会被覆盖。
显示调用 :
在子类init方法里:
父类名.init(参数)
定义:
class Phone2012(父类名字)
类内容体
# 多继承 用逗号隔开
class Phone2012(父类名字1,父类名字2)
pass # 使用pass关键字 占位 让语法不报错
#如果有同名成员或者方法 左边优先级最高
重写后-调用父类成员或方法:
使用super()或者父类名字.
class Phone2012(父类名字)
#方法1
def say(self):
print(父类名字.父类属性) #用父类名称.属性或者方法可以调用父类方法
print(父类名字.父类方法(self)) #如果调用父类方法 必须传入self
#方法2
def say(self):
print(super().父类属性) #用super()关键字
4.类方法 @classmethod
- 类方法可以直接类名调用,也可以实例去调用
- 必须使用@classmethod床十七
- 形参为cls
- 类方法不能访问实例属性,只能访问类属性
class Student()
def say(self,name):
self.name=name
@classmethod
def classmethodemo(cls): #一般形参为cls
print("这是个类方法")
5.静态方法 @staticmethod
- 使用@staticmethod 装饰器
- 不能访问实例属性,也不能访问类属性
- 可以直接类名调用,也可以实例去调用
class Student()
def say(self,name):
self.name=name
@staticmethod
def classmethodemo():
print("这是个静态方法")
二十一、类的魔术方法
1.init
#类的构造器 创建类时会默认调用
class Student
name:"张三"
def __init__(self,name,age): # init方法创建对象自动执行 相当于js的构造器 参数为形参
self.name=name
self.age=age #如果类里没有定义 这一步会创建
stu_1=Student("张三",18)
#如果 没有使用str 会打印内存地址
2.str
class Student
name:"张三"
def __str__(self): # str方法适用于访问类对象的时候返回值 相当于js toString
return f"我的名字是{self.name}"
stu=Student("张三")
print(stu) # 我的名字是张三
3.lt
class Student
def __init__(self,age):
self.age=age
def __lt__(self,other): # lt 用于类对象直接比较 返回一个布尔 self当前对象 other是其他对象
return self.age<other.age
stu1=Student(15)
stu2=Student(14)
print(stu1 < stu2) #false
4.le
class Student
def __init__(self,age):
self.age=age
def __lt__(self,other): # le 同于lt 比较时候多了等于
return self.age<=other.age
stu1=Student(15)
stu2=Student(14)
print(stu1 <= stu2) #false
4.eq
class Student
def __init__(self,age):
self.age=age
def __eq__(self,other): # eq 同于相等比较
return self.age==other.age
stu1=Student(15)
stu2=Student(15)
print(stu1 == stu2) #true
#如果不使用eq 那么比较内存地址
二十二、类型注释
1.变量
#方法1使用: 同ts
var_1:int=10 #使用:定义
#方法2使用注释# type:
var_2=10 # type:int
2.函数
参数定义同ts
->类型 定义返回值
def add(x:int,y:int)->int:
return x + y
#参数定义同ts
#->类型 定义返回值
3.Union联合类型
导包:form typing import Union
Union[类型,...,类型]
form typing import Union
list :List[Union[int,str]]=[1,2,'hello']
二十三、线程
1.相关模块
1.threading python3之后的模块
2._thread :python3之前的thread模块的重命名 一般很少使用
2.创建线程
#方法一
import threading
t1=threading.Thread(target=参数1,args=(参数2))
# 参数1 为目标函数 参数2为参数 元组形式 多个逗号隔开
t1.start() #启动
#方法二 以类的方式
class MyThread(threading.Thread):
def __init__(self,name):
super().__init__() #调用父类的初始化方法 保证父类初始化成功
self.name=name
def run(self): #重写父类run方法 定义在新的线程类要完成的task
print(123)
t1=MyThread("线程1")
3.方法
t1=threading.Thread(target=参数1,args=(参数2))
t1.start() #启动
t1.join() #让主线程等待 子线程执行
4.线程通信
from queue import Queue
q=Queue(maxsize=1) #定义队列 队列最多消息为1
q.put() #发送消息 如果消息慢了会阻塞队列
q.get() #取出消息 每次取出消息 消息队列长度-1 如果长度为0 会阻塞线程
5.线程消息隔离(线程内部全局变量)
变量直接互不影响
import threading
local_data=threading.local()
local_data.name='local_data'
#此时主线程local_data.__dict__ 就为local_data
6.线程池
from concurrent.futures import ThreadPoolExecutor
#创建新的线程池对象 最大线程数为3
executor = ThreadPoolExecutor(max_workers=3)
#提交任务到线程池,参数只需要方法名字,不需要(),参数为方法的参数用逗号隔开,依次写 立即返回,不会阻塞主线程
#如果任务数超过任务书 会等待可用线程
task1=executor.submit(方法名称,参数xx)
task1.done() #检查任务是否完成 返回true或false 存在问题(处于当前时间是否,不知道任务多久完成)
task1.cancel() #取消任务 该任务没有放入到线程池中才能取消成功 返回true和false
task1.result() #拿到任务结果 是阻塞方法会阻塞主线程
#---------获取全部结果---------
#as_completed 获取所有结果 像promise.all
urls=[1,2,3]
all_task=[executor.submit(xxx,url) for url in urls]
for item as_completed(all_task):
data=item.result() #获取返回结果 先执行先返回
# map 也是获取所有结果
for item in executor.map(方法名,方法参数数组) #item 为结果 根据数组顺序得到结果
#wait() 方法
from concurrent.futures import wait
wait(all_task,return_when=FIRST_COMPLETED) #让主线程等待
#return_when 值:FIRST_COMPLETED只要有一个执行完毕就执行主线程 ALL_COMPLETED所有执行完
7.线程同步信号量 Semaphore -控制最大线程数量并发
import threading
sem=threading.Semaphore(value=4)#最大线程为4
sem.acquire() #获取锁
sem.release() #释放锁
二十四、进程
1.创建线程
import multiprocessing
#方法一
p1=multiprocessing.Process(target=参数1,args=(参数2))
# 参数1 为目标函数 参数2为参数 元组形式 多个逗号隔开
#方法二 以类的方式
class MyProcess(multiprocessing.Process):
def __init__(self,name):
super().__init__() #调用父类的初始化方法 保证父类初始化成功
self.name=name
def run(self): #重写父类run方法
print(123)
t1=MyThread("线程1")
2.方法
p1=multiprocessing.Process(target=参数1,args=(参数2))
p1.start() #启动
p1.join() #让主进程等待 子进程执行
3.进程通信
import multiprocessing
q=multiprocessing.Queue(maxsize=1) #定义队列 最大进程数量1
q.put() #发送消息 如果消息慢了会阻塞队列
q.get() #取出消息 每次取出消息 消息队列长度-1 如果长度为0 会阻塞线程
4.进程池
#方法一:
from concurrent.futures import ProcessPoolExecutor
#参照线程池使用方法 一样
#方法二
import multiprocessing
pool=multiprocessing.Pool(multiprocessing.cpu_count()) #设置cpu核心数 不要大于当前cpu核心数
#multiprocessing.cpu_count() 方法获取当前cpu的核心数
result=pool.apply_async(函数名字,args(3,))#args(3,) 函数参数 是元组类型
popl.close() #必须在join前调用close
popl.join()#阻塞主进程
print(result.get()) #拿到子进程的结果
#获取多任务结果
for result in pool.imap(函数,[参数列表])
print(result)#结果 按照输入顺序
for result in pool.imap_unordered(函数,[参数列表])
print(result)#结果 先出先输出
5.进程和线程的区别,应用场景
多进程优点:独立运行,互不影响
多进程缺点:创建进程的代价非常大
多线程优点:效率比较高,不会耗费大量资源。
多线程缺点:稳定性较差,一个崩溃后会影响整个进程。
应用:
多进程适用场景:对于计算密集型任务,比较适合多进程。
多线程适用场景:适合 IO 密集型任务,比如文件读取以及爬虫等操作
二十五、协程
1.可迭代对象
1.1什么是可迭代对象
定义 了可返回一个迭代器__iter__
或
定义了可支持下标索引的__getitem__方法
1.2 如何判断是可迭代对象
#方法1
from collections import Iterable #迭代对象
print(isinstance([],Iterable))
#方法2
hasattr([],"__getitem__") #true 判断有无__getitem__方法
1.3 如何定义__getitem__方法
class Employee:
def __init__(self,list):
self.list=list
def __getitem__(self,index):
return self.list[index]
emp=Employee([1,2,3,4])
for i in emp:
print(i)#1,2,3,4
2.迭代器对象
1.1什么是迭代器
迭代器就是实现了__next__和__iter__方法(缺一不可)的对象,就叫迭代器。
其中__iter__方法返回迭代器自身,
__next__方法不断返回迭代器中的下一个值
直到容器中没有更多的元素时则抛出Stoplteration异常,以终止迭代
二十六、锁
1.GIL全局解释器锁
GLL 全局解释器锁在什么时候会释放:
(1)当当前的执行线程在执行 IO 操作时,会主动放弃 GIL。
(2)当当前执行的线程执行了 100 条字节码的时候,会自动释放 GIL锁。
GIL 全局解释器锁是粗粒度的锁,必须配合线程模块中的锁才能对每个原子操作进行锁定
2.手动加锁
import threading
lock = threading.Lock()
lock.acquire()#获取锁
lock.release()#释放
#方法二: 使用with 自动获取和释放
with lock:
global num
num +=1
二十七、装饰器
1.使用
无参数
def timer(func):
def doce(*args, **kwargs):
print(123)
func(*args, **kwargs)
return doce
@timer #等同于 fn=time(fn)
def fn():
print(456)
fn()
#先输出123
#后输出456
#相当于 给输出456的方法执行前 先执行123装饰器方法
有参数
def timer(name):
print(name)
def doce(func):
def doce1(*args, **kwargs):
func(*args, **kwargs)
return doce1
return doce
@timer("张三")
def fn(age):
print(age)
fn(18)
有返回值
def timer(name):
print(name)
def doce(func):
def doce1(*args, **kwargs):
result = func(*args, **kwargs)
return result
return doce1
return doce
@timer("张三")
def fn(age):
print(age)
return 123
print(fn(18))
2.定义装饰器
#(1)被装饰函数带有参数或不带参数
def deco(func):
def inner(*args,**kwargs):
func(*args,**kwargs)
return inner
# (2) 装饰器本身带参数
def deco1(parma): # param是装饰器本身的参数
def outer(func): # 以被装饰的函数名作为参数
def inner(*args,**kwargs)
func(*args,**kwargs)
return inner
return outer
#(3) 被装饰函数带返回值
def deco2(parma): # param是装饰器本身的参数def
def outer(func): # 以被装饰的函数名作为参数
def inner(*args,**kwargs):
result = func(*args,**kwargs) # 接收到被装饰函数的返回值
return result# 返回被装饰函数的返回值
return inner
return outer
二十八、event对象
import threading
event = threading.Event()
#重置event对象 使所有的event事件都处于待命状态
event.clear()
#阻塞线程 等待event指令
event.wait()
#发送event指令,使得设置该event事件线程执行
event.set()
二十九、Condition对象
import threading
cond = threading.Condition()
class Ximige(threading.Thread):
def __init__ (self, cond, name):
threading.Thread.__init__(self, name=name) #父类方法
self.cond = cond
def run(self):
self.cond.acquire() #获取锁
self.cond.wait() #等待
self.cond.notify() #唤醒其他wait状态的线程
self.cond.release() #释放锁
ximige=Ximige(cond,'西米哥')
未完待续
转载自:https://juejin.cn/post/7244802984119320636