由于公司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("和") #27.len() 统计字符串长度
name=" 张山和李四和"
len(name) #68.find() 查找字符串是否出现
str='123'
str.find("4") #-1
#是-返回第一次出现的下标  不是-返回-19.caitalize() 首字母大写
str='hello'
str.caitalize() #Hello10.isdigit() 是否只包含纯数字字符
num="123"
num.isdigit()#true11.islower() 是否全部包含小写字符
s="heelo"
s.islower()#true12.lower() 全部变成小写 upper()全部变成大写
s="Hello"
s.lower()#hello
s.upper()#HELLO13.startwith() 是否以某个字符开头 endwith()是否以指定字符结尾
s="hello"
s.startwith("h")#true
s.endwith("o")#true14.* 重复生成多个
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为24.不固定参数 *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+y6.函数类型定义
def add(x:int,y:int)->int:
    return x + y
#参数同ts  
#->类型  定义返回值八、列表
1.下标可以是 负数
九、列表方法
1.arr.index(元素) 查询下标
arr=[1,2,3,4]
arr.index("1")  
#解析:元素存在返回下标,不存在 抛出异常
#返回:02.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的数量 只能统计第一层 二维数组里 无法统计
#返回:29.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 和false14.max()最大值,min()最小值
#只适合于纯数字的列表
a=[1,2,3]
print(max(a)) #3
print(min(a)) #115.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)  #23.不支持修改(增加和删除)
如果元组嵌套列表,列表里面的值可以修改
十一、切片
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)#39. 并集 | 交集&
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("李四") #没有不会异常 返回None3.删除pop
dict={"张三":12,"李四":14}
val=dict.pop("张三")
#参数为键名  
#返回被删除的元素 原字典{"李四":14}
#此时 dict为{"李四":14}
val=dict.pop("w","not exist")
#删除的键不存在会异常 第二个参数会默认给返回值不会异常
#此时 val 为not exist4.清空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  146.获取长度 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) #true10.setdefault 和get类似 不存在会添加
dict={"张三":12}
dict.setdefault("李四",13)#返回13
#如果key存在返回 对应的value  
#如果不存在 就改变原字典 新增key 如果存在第二个参数有的话值 value为第二个参数
#没有第二个参数 value 默认为None11.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)#Trueisinstance() 与 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) #false4.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) #false4.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:int2.函数
参数定义同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_data6.线程池
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,42.迭代器对象
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,'西米哥')









