由于公司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集合 |
name = "张三"
print(type(name))
#
任何类型都可以转字符串
str=(11)
需要确保字符串内容全是数字
浮点转整数-去除小数部分
整数浮点 补充.0 如11 =>11.0
使用:定义数据类型 或者 用注释#type:
var_1:int=10 #使用:定义 同于ts
var_2=10 # type:int
-+ 、-=、 *=、 /=、 %= 、**= 、//=
- 大小写敏感,如变量可以作为两个变量 如:a 和 A
- 不能用关键字 如:False True None And… 必须要大小写一样
def getName(){
global name="张三"
}
#需要修改外部的全局变量 需要再函数内部 用global
可以单引号、双引号、三引号(注释)
引号嵌套:字符串要包含引号可以使用\转义
a='123'
b="123"
c='''
123
123
'''
%s | 将内容转换为字符串,放入占位位置 |
---|---|
%d | 将内容转换为整数,放入占位位置, |
%5d | 表示将整数的宽度控制在5位,如果不足用空格补充,如果限制数字位数小于原数字 那么不会生效 |
%f | 将内容转换为浮点型,放入占位位置 |
%5.2d | 表示将整数的宽度控制在5位,小数精度为2,如果不足用空格补充 |
%.2d | 只限制小数 |
#方式1
"{} {}".format("hello", "world")
'hello world'
#方式2
"{1} {0} {1}".format("hello", "world")
'world hello world'
name="张山李四"
name.index("李四")#2
#返回:命中的第一个下标 没有命中报错
name="张山李四"
#最大替换次数,如不设置 则全部替换
str=name.replace("张三","李四")
#返回:李四李四
name="张山和李四"
arr=name.split("和")
#解析:以 和 切割数组
#返回:[张三,李四]
name=" 张山和李四 "
#不传入参数
name.strip() #去除首位空格
#返回:"张山和李四"
#传入参数 去除两边字符 没办法除去中间
str="12ASSDF21"
str.strip("12")
#解析:不按照参数顺序 12或者21都要去除
#返回"ASSDF"
name=" 张山和李四和 "
name.count("和") #2
name=" 张山和李四和"
len(name) #6
str='123'
str.find("4") #-1
#是-返回第一次出现的下标 不是-返回-1
str='hello'
str.caitalize() #Hello
num="123"
num.isdigit()#true
s="heelo"
s.islower()#true
s="Hello"
s.lower()#hello
s.upper()#HELLO
s="hello"
s.startwith("h")#true
s.endwith("o")#true
a="b"
print(a*3)#bbb
rang(10)
表示[0,1,2,xxxx,9]
rang**(5,10)
表示[5,6,7,8,9] 包头不包尾
rang(5,10,2)
第三个参数 数字间隔2 (步长)。 5,7,9
def 函数名(参数):
#函数体
retrun 返回值
def fn():
retrun 1,2 #变量用,隔开
x,y=fn() #多个值接受
# x为1 y为2
# 方法一:位置不定长
def fn(*args):
print(args)
fn("tom",15)
# ("tom",15) 得到元组类型
# 方法二: 关键字不定长
def fn(**kwargs): # 参数必须是key=vale
print(kwargs)
fn(name='张三')
# {name='张三'} 得到字典类型
lambda 传入参数:函数体(一行代码)
lambda x,y:x+y
def add(x:int,y:int)->int:
return x + y
#参数同ts
#->类型 定义返回值
arr=[1,2,3,4]
arr.index("1")
#解析:元素存在返回下标,不存在 抛出异常
#返回:0
arr=[1,2,3,4]
arr.insert(0,"5")
#解析:插入 第一个参数下标 第二个参数元素
#改变后arr为 [5,1,2,3,4]
arr=[1,2,3,4]
arr.append(5)
#解析:尾部插入 相当于push
#改变后arr为[1,2,3,4,5]
arr=[1,2,3,4]
arr1=[5,6]
arr.extend(arr1)
#解析:拼接数组 相当于concat
#改变后arr为[1,2,3,4,5,6]
#----------------改变原数组
arr=[1,2,3]
del arr[0]
#解析:删除指定下标数据
#改变后arr为[1,2]
arr=[1,2,3]
arr.pop(0)
#解析:删除下标为0的元素 返回删除具体元素
#返回:1
#改变后arr为[2,3]
arr=[1,2,3,1]
arr.remove(1)
#解析:删除指定匹配的第一个元素
#改变后arr为[2,3,1]
arr=[1,2,3,1]
arr.clear()
#解析:清空数组
#改变后arr为[]
arr=[1,2,3,1]
conut=arr.count(1)
#解析:统计列表内1的数量 只能统计第一层 二维数组里 无法统计
#返回:2
arr=[1,2,3,1]
conut=len(arr)
#解析:获取数组长度
#语法:sorted(容器,reverse) reverse表示正序或者反序 不传默认正序
list=[3,2,5,1]
sorted(list)
#[1,2,3,4,5]
#语法: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)
a=[1,2]
b=[3,4]
c=a+b #[1,2,3,4]
#----------------得到新数组不会改变原数组
arr=[1,2]
print(arr*3) #[1,2,1,2,1,2] 重复三次
a=[1,2,3]
print(1 in a) #判断1是不是在a数组中 返回true 和false
#只适合于纯数字的列表
a=[1,2,3]
print(max(a)) #3
print(min(a)) #1
a=["Z","N","2","1"]
a.reverse()
print(a)#["1","2","N","Z"]
t1=(1,"hello",True)
t2=()
t3=tuple()
#------------如果是单独的元素必须加上逗号 不然不会认定为元组
t4=(1,)
元组不支持修改 目前支持三个方法 find、count、len() 或者切片
arr=(1,"hello")
arr.find("hello") #1
arr.count("hello") #1
print(arr[0:1])#(1,"hello") 切片
len(arr) #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.用{}定义 set={“张三”,“李四”,“王五”}
2.用set() my_set=set() #定义空集合
#重点:集合无下标, 只有不可变的数据类型才能加入集合
python
set={"张三","李四","王五"}
set.add("HELLO") #{"张三","李四","王五","HELLO"}
set={"张三","李四","王五"}
set.remove("王五")#{"张三","李四"}
set={"张三","李四","王五"}
ele=set.pop()
#取出元素后 改变原有的set 有返回值 ele就是随机取出的数
set={"张三","李四","王五"}
set.clear()
#该集合被清空 {}
set1={1,2,3}
set2={1,5,6}
set3=set1.difference(set2)
#解析:以set1为标准获得set2的差级
#set3为{2,3} 原有的集合不变
set1={1,2,3}
set2={1,5,6}
set1.difference_update(set2)
#相处set1相比set2相同的
#此时set1 为{2,3}
#set2不会发生变化
set1={1,2,3}
set2={1,5,6}
set3=set1.unior(set2)
#合并set1和set2
#set3为{1,2,3,5,6}
#set1和set2不会发生改变
set1={1,2,3}
l=len(set1)#3
a={1,2,3}
b={3,4,5}
print(a|b) #{1,2,3,4,5}
print(a&b) #{3}
使用{}或dict() 例:dict=dict()
存储元素为:键值对,例:{key:value,key:value}
dict={"张三":12}
#方法一:
dict["张三"]
#如果不存在的属性 会异常
#方法二:
dict.get("李四") #没有不会异常 返回None
dict={"张三":12,"李四":14}
val=dict.pop("张三")
#参数为键名
#返回被删除的元素 原字典{"李四":14}
#此时 dict为{"李四":14}
val=dict.pop("w","not exist")
#删除的键不存在会异常 第二个参数会默认给返回值不会异常
#此时 val 为not exist
dict={"张三":12,"李四":14}
dict.clear()
dict={"张三":12,"李四":14}
for key in dict.keys()
print(key) #张三 李四
for value in dict.values()
print(value) #12 14
d1={name:'1'}
d2=d1.copy()
#只能拷贝第一层
list=["name","age","address"]
d3=dict.fromkeys(list,'Null') #第一个参数为列表 第二个参数为列表的值
#d3 = {"name":"Null","age":"Null","address":"Null"}
dict={"张三":12}
print("张三" in dict) #true
dict={"张三":12}
dict.setdefault("李四",13)#返回13
#如果key存在返回 对应的value
#如果不存在 就改变原字典 新增key 如果存在第二个参数有的话值 value为第二个参数
#没有第二个参数 value 默认为None
dict={"张三":12}
dict1={"张三":13,"李四":14}
dict.update(dict2)
#dict 此时为{"张三":13,"李四":14}
#原有的键和新的一样那么会更新新的 没有的会添加
dict={"张三":12,"李四":14}
dict.popitem() #随机删除一个键值对
获取长度
最大元素
最小
- list()
- str()
- tuple()
- set()
参数为容器
大致理解为:查看对象属性和方法
dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;
带参数时,返回参数的属性、方法列表
#判断一个对象是否是一个已知的类型(是不是实例)
a = 2
isinstance (a,int)#True
isinstance() 与 type() 区别:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
#objects -- 复数,表示可以一次输出多个对象。输出多个对象时,需要用 , 分隔。
#sep -- 用来间隔多个对象,默认值是一个空格。
#end -- 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符串。
#file -- 要写入的文件对象。
#flush -- 输出是否被缓存通常决定于 file,但如果 flush 关键字参数为 True,流会被强制刷新。
# 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")
with.open("python.text","r",encodeing="UTF-8") as f
# f为文件对象名字
1.文件对象.read(num) # 读取文件内容 num 表示读取字节数 比如10个字节 不传默认全部
如果连续调用两次 下一个会从上一个内容后继续读取
2.文件对象.readLines() #按行读取 读取成菜单 会读出\n 读取全部文字 返回一个列表
也会继承上次read读取内容 下一个会从上一个内容后继续读取
3.文件对象.readLine() #只读取一行 多次调用读取多行
######.可以使用for 读取 也会收到read影响
文件对象.close()
解除占用
文件对象.write(“hello”)
写入到内存,一般保存图片之类的
文件对象.writelines(参数)
接受一个可迭代对象 比如列表或元组 需要换行必须在每个元素后加入\n
对象.flush()
刷新 保存
#tell() 获取当前指针位置
文件对象.tell()
#seek() 移动指针
文件对象.seek(参数1,参数2)
#参数1 偏移量
#参数2 偏离相对位置 0是开头 1是相对当前位置唯一 2是末尾 如果以文本模式打开 只能取0 二进制无所谓
try:
# 代码
except:
# 异常处理
else:
#没有异常
finally:
#有或者没有 都要执行
try:
# 代码
except NameError as e:
#except [异常名 as 别名]:
# 异常处理
# NameError 为指定异常 as e设置异常对象别名为e
#多个异常可以用(NameError,ZeroDivisonError) 括号包裹 逗号隔开
#捕获多个异常 可以用 Exception 或者直接except:
#方法一
raise #无参数 引发当前上下文捕获的异常 例 如果在except中就抛出当前异常 不在的或默认RuntimeError
#方法二
raise 异常名 #引发指定异常
#方法二
raise 异常名(描述信息) #引发指定异常 同时附带描述信息
class AuctionException(Exception): #必须继承Exception父类 自定义异常名字类
pass #pass关键字占位
#使用
raise AuctionException("自定义错误内容")
try:
XXXX
except AuctionException as e
print(e) #自定义错误内容
[from 模块名] import [模块 | 类 | 变量 | 函数 |][as 别名]
常用:
import 模块名
from 模块名 import 类、变量、方法
from 模块名 import *
import 模块名 as 别名
from 模块名 import 功能名 as 别名
例如:
import time
time.sleep(5)
from time import *
sleep(5)
import 自定义文件名
如果在自定义模块里 有调用函数方法 导入会直接调用
如果非要写 但是不想调用 用__main__
例: if name==“main”: __name__是python内置变量 右键调试会把name变成main
fn()
自定义模块指定导出 限制于 import *
all=[“fn”]
def fn():
XXX
def fn1():
XXX
此时 如果用*导入那么只能用fn 不能用fn1
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) #开方 返回浮点数
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个数字 返回一个数组
import 包名.模块名字
from 包名 import 模块名字
from 包名.模块名字 import 方法
# pip install 包名 (等同于npm 安装python自带)
#国内镜像
#pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名
1.编辑器右下角 python版本号 点击
2.interpreter settings 点击
3.当前有包的列表 点击左上角加号
4.搜索 点击下 install package
5.右侧的Options 里可以加入镜像网址https://pypi.tuna.tsinghua.edu.cn/simple
import json
data=[{"name":"张三"}]
str=json.dumps(data,ensure_ascii=False) # ensure_ascii表示不使用编码 直接转
import json
data='[{"name":"张三"}]'
l=json.loads(data)
from pyecharts.charts import Line
Tine = Line()
Tine.add_xaxis(["中国"])
line.add_yaxis ("GDp",[30,20,10])
Tine. render()
#右键运行后 同级会生成一个render.html文件 进入文件编辑器右上角自带预览
操作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()#关闭
class Student
name=None
def say(self,参数2):
#要访问成员属性 需要self.name self代表自己
#参数2为形参
stu_1=Student()
stu_1.name="张三"
#和js不同的是不需要new关键字
class Student
__name=None #私有变量
def __say(self): #私有方法
print()
#在类的内部可以使用 私有变量 实例访问不了
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()关键字
class Student()
def say(self,name):
self.name=name
@classmethod
def classmethodemo(cls): #一般形参为cls
print("这是个类方法")
class Student()
def say(self,name):
self.name=name
@staticmethod
def classmethodemo():
print("这是个静态方法")
#类的构造器 创建类时会默认调用
class Student
name:"张三"
def __init__(self,name,age): # init方法创建对象自动执行 相当于js的构造器 参数为形参
self.name=name
self.age=age #如果类里没有定义 这一步会创建
stu_1=Student("张三",18)
#如果 没有使用str 会打印内存地址
class Student
name:"张三"
def __str__(self): # str方法适用于访问类对象的时候返回值 相当于js toString
return f"我的名字是{self.name}"
stu=Student("张三")
print(stu) # 我的名字是张三
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
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
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使用: 同ts
var_1:int=10 #使用:定义
#方法2使用注释# type:
var_2=10 # type:int
参数定义同ts
->类型 定义返回值
def add(x:int,y:int)->int:
return x + y
#参数定义同ts
#->类型 定义返回值
导包:form typing import Union
Union[类型,…,类型]
form typing import Union
list :List[Union[int,str]]=[1,2,'hello']
1.threading python3之后的模块
2._thread :python3之前的thread模块的重命名 一般很少使用
#方法一
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")
t1=threading.Thread(target=参数1,args=(参数2))
t1.start() #启动
t1.join() #让主线程等待 子线程执行
from queue import Queue
q=Queue(maxsize=1) #定义队列 队列最多消息为1
q.put() #发送消息 如果消息慢了会阻塞队列
q.get() #取出消息 每次取出消息 消息队列长度-1 如果长度为0 会阻塞线程
变量直接互不影响
import threading
local_data=threading.local()
local_data.name='local_data'
#此时主线程local_data.__dict__ 就为local_data
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所有执行完
import threading
sem=threading.Semaphore(value=4)#最大线程为4
sem.acquire() #获取锁
sem.release() #释放锁
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")
p1=multiprocessing.Process(target=参数1,args=(参数2))
p1.start() #启动
p1.join() #让主进程等待 子进程执行
import multiprocessing
q=multiprocessing.Queue(maxsize=1) #定义队列 最大进程数量1
q.put() #发送消息 如果消息慢了会阻塞队列
q.get() #取出消息 每次取出消息 消息队列长度-1 如果长度为0 会阻塞线程
#方法一:
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)#结果 先出先输出
多进程优点:独立运行,互不影响
多进程缺点:创建进程的代价非常大
多线程优点:效率比较高,不会耗费大量资源。
多线程缺点:稳定性较差,一个崩溃后会影响整个进程。
应用:
多进程适用场景:对于计算密集型任务,比较适合多进程。
多线程适用场景:适合 IO 密集型任务,比如文件读取以及爬虫等操作
定义 了可返回一个迭代器__iter__
或
定义了可支持下标索引的__getitem__方法
#方法1
from collections import Iterable #迭代对象
print(isinstance([],Iterable))
#方法2
hasattr([],"__getitem__") #true 判断有无__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
迭代器就是实现了__next__和__iter__方法(缺一不可)的对象,就叫迭代器。
其中__iter__方法返回迭代器自身,
__next__方法不断返回迭代器中的下一个值
直到容器中没有更多的元素时则抛出Stoplteration异常,以终止迭代
GLL 全局解释器锁在什么时候会释放:
(1)当当前的执行线程在执行 IO 操作时,会主动放弃 GIL。
(2)当当前执行的线程执行了 100 条字节码的时候,会自动释放 GIL锁。
GIL 全局解释器锁是粗粒度的锁,必须配合线程模块中的锁才能对每个原子操作进行锁定
import threading
lock = threading.Lock()
lock.acquire()#获取锁
lock.release()#释放
#方法二: 使用with 自动获取和释放
with lock:
global num
num +=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))
#(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
import threading
event = threading.Event()
#重置event对象 使所有的event事件都处于待命状态
event.clear()
#阻塞线程 等待event指令
event.wait()
#发送event指令,使得设置该event事件线程执行
event.set()
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,'西米哥')