目录
快捷键
格式输出
变量类型
运算
循环与判断
if 条件语句
while循环语句
for遍历语句
序列操作
字符串 str
列表 list
元组 tuple
集合 set
字典 dict
推导式
生成器与迭代器
可迭代对象
迭代器
生成器
三者关系
函数与装饰器
函数定义
简化函数
递归函数
装饰器
常用函数
常用三方库
随机数
时间
日期时间
哈希加密
文件处理
TRY及异常处理
类 CLASS
类的定义与调用示例:
继承
封装
多态
模块
导入与自定义
进程与线程
进程
自定义进程
进程池
进程间的通讯,队列
线程
全局解释器锁GIL
死锁
生产者与消费者
协程
正则表达式
常用正则表达式:
普通输出
print(f'...{变量}...') print('...%d...%f...%s...', % (整型变量,浮点变量,字符变量)) print('...{}...'.format(变量))特殊输出
print('..."双引号内容"...\'单引号内容\'...') #含引号数据的输出 print('...%.3f...%06d...', % (变量1,变量2)) #输出3位小数,6位整数(前面用0补齐) print('...\n...\t...') #换行符,制表符Tab print('...',end='结束符') #设置结束符,默认\n
可变类型:列表、集合、字典
不可变类型:整型、浮点型、字符串、元组
type(数据) #检测数据类型 int(数据) #转换为整型 str(数据) #转换为字符型 list(数据) #转换为列表 set(数据) #转换为集合 tuple(数据) #转换为元组 chr(数据) #ASCII转字符或Unicode转中文 ord(数据) #字符转ASCII或中文转Unicode eval(数据) #字符串中有效数据自动转型 a,b=b,a #变量值互换 id(变量) #变量地址
格式:
if条件1: 条件1成立时的任务 elif条件2: 条件2成立时的任务 else: 所有条件均不满足时的任务
三目运算:
c = 返回值1 if 条件 else 返回值2 #若条件成立赋值1,否则赋值2例如:
c = a if a>b else b # c等于a和b中较大者
格式:
while 条件1: #当满足条件1时,执行循环 任务1 if 条件2: #当满足条件2时,跳出此层循环 任务2 break if 条件3: #当满足条件3时,结束此次循环,直接进入下一次循环 任务3 continue if 条件4: #当满足条件4时,跳出所有循环,结束进程 任务4 return 任务5 #上述条件均不成立时执行此任务 else: 任务6 #循环正常完成后的任务,若循环不开始或者跳出,则不执行 任务7 #循环外的任务注意:
如果是限次循环,需要重复n次,初始值为c,则条件是<n+c
一般在循环最后进行 i+=1 的操作,注意continue所对应的任务中需要单独进行 i+=1 的操作
while语法常常用于需要持续执行任务,或者需要等待触发等情况
如果while中还有内部循环,可通过break跳出当前层循环,或者return跳出所有循环结束进程
while True: 任务1 if 触发条件: 任务2 break 任务3 for i in range(100): 任务4 if 跳出此层循环条件: 任务5 break if 跳出所有循环条件: 任务6 continue 任务7
格式:
for 临时变量 in 序列: 任务1 if 条件2: #当满足条件2时,跳出此层循环 任务2 break if 条件3: #当满足条件3时,结束此次循环,直接进入下一次循环 任务3 continue if 条件4: #当满足条件4时,跳出所有循环,结束进程 任务4 return 任务5 #上述条件均不成立时执行此任务 else: 任务6 #循环正常完成后的任务,若循环不开始或者跳出,则不执行 任务7
索引 [m,n) 范围内按步长b切片
若m、n为负数表示反向索引,倒数第m位
若b为负数表示反向切割
str.split(子串或字符, 次数)切割掉子串或字符,剩余部分以列表返回
str.replace(旧子串, 新子串, 次数)将旧子串替换为新子串
当新子串为空时,可作为删除子串使用
str.remove(子串)
移除首个指定子串
str.clear()清空字符串变量
str.append(子串)末尾添加子串 str.insert(索引, 子串)在索引处插入子串 str.find(目标子串, m, n)索引 [m,n) 范围内查找子串首次出现的索引
rfind表示从右往左查找
若未找到返回-1
str.index(目标子串, m, n)索引 [m,n) 范围内查找子串首次出现的索引
rindex表示从右往左查找
若未找到报错
str.count(目标子串, m, n)统计 [m,n) 范围内子串出现的次数 str.strip()两侧删除空白字符
rstrip()删除右侧空白
lstrip()删除左侧空白
str.capitalize()字符串首字符大写 str.title()字符串中所有单词首字母大写 str.upper()所有小写转大写
lower()所有大写转小写
str.ljust(数据长度, '填充内容')数据长度内左对齐,不足时自动填充
rjust(数据长度, '填充内容')右对齐
center(数据长度, '填充内容')居中对齐
str.startswith(子串, m, n)判断 [m,n) 范围内是否以子串开始
endswith(子串, m, n)判断结束
str.isalpha()判断是否全部由字符构成
isdigit()判断是否全部由数字构成
isalnum()判断是否全部由数字、字符构成
isspace()判断是否全部由空格构成
子串 in str判断是否含有子串
not in判断不含子串
'起始字串'.join(字串列表)将列表中的所有字串合并成一个字符串 str.reverse()将字符串逆序 str.copy()复制,str变化,则变量同时变化 len(str)字符串长度 str1 + str2合并两个字符串
常用的批量存储
格式:[数据1, 数据2, ..., 数据n]
元组数据不能修改
格式:(数据1, 数据2, ..., 数据n)
格式作用tuple()创建空元组tuple.index(i)索引第 i 位元素tuple.count(元素)元素出现次数len(tuple)元组容量tuple1 + tuple2元组合并
无重复数据存储,常用于去重
格式:{数据1, 数据2, ..., 数据n}
格式作用set()创建空集合set.add(数据)添加元素set.update(list)添加数据序列set.remove(数据)删除元素set.discard(数据)删除元素set.pop()随机删除元素,并返回该元素
以键值对的形式对应存储数据
格式:{'key1': 数据1, 'key2': 数据2, ... ..., 'key': 数据}
格式作用dict{}创建空字典dict[key] = 数据更改数据/添加键值对dict[key].del()删除键值对dict.clear()清空字典dict.get(key, 返回值)按key查找,若未找到返回设定值,默认为Nonedict.keys()获取key列表dict.values()获取数据列表dict.items()拆包字典,返回 [(key1, 数据1), (key2, 数据2), ...]
生成器gen、迭代器iter、列表list、元组tuple、字符串str、集合set、字典dict
判断是否可迭代:
from collections import Iterable isinstance(对象, Iterable)
可以被next()调用并返回下一个值的对象,称为迭代器iteration
iter(可迭代对象) #将可迭代对象转化为迭代器
近似等同于推导式,但节省内存,即用即推
g=推导式 g.__next()__ # 通过调用生产元素,每次调用生产一个,顺序向下 next(g) # 同上 def func: ... yield g # 定义g为生成器,等效于"returng并暂停保存g" g.send(值) # 向生成器传值,初次传入None
通过下面的代码加深理解
""" 费莫纳契数列【1,1,2,3,5,8,13。。。】 """ def Femonacci(length): # 费莫纳契数列元素生成器 a,b=0,1 n=0 while n < length: yield b a,b=b,a+b n+=1 return 'no rest' byte = 8 #数列长度 Fmnc_list = [] g = Femonacci(byte) for i in range(byte): #循环调用生成器,自动生成指定长度的数列 element = next(g) print(element,end='') Fmnc_list.append(element) print('\n',Fmnc_list) #............................................................................... """ 利用生成器进行多协程工作,让多种工作交替执行,或分组执行 """ def task1(j): for i in range(j): print(f'正在搬第{i}块砖') yield None def task2(j): for i in range(j): print(f'听第{i}首歌') yield None n = 5 g1 = task1(n) g2 = task2(n) while True: try: g1.__next__() g2.__next__() except: pass
生成器 ∈ 迭代器 ∈ 可迭代对象
除迭代器外,可迭代对象还包括 列表、元组、集合、字典、字符串
以map、lambda、filter、reduce、sorted为例
""" 利用lambda匿名函数进行偶数判断 用map自动将list1中的元素进行函数处理 """ list1 = [1,2,4,6,4,6,3,8,6,4,6,3,9] result1 = map(lambdax : x if x % 2 == 0 else x + 1, list1)#嵌套函数简化 print(list(result1))#结果转换为列表格式输出 """ 利用lambda匿名函数进行求和 用reduce自动将tuple中的元素进行函数处理 """ from functools import reduce tuple1 = (3, 5, 7, 8, 9, 1) result2 = reduce(lambda x, y : x + y, tuple1, 10) #初始值为10,对元组tuple1内所有元素,进行加法处理 print(result2) """ 利用lambda匿名函数进行判断大于10 用filter自动将list2中符合体条件的元素存入新列表 注意:filter不改变原列表 """ list2 = [12,6,8,98,34,36,67,3,0] result3 = filter(lambda x : x > 10, list2) #对list2中所有元素筛选出大于10的元素 print(list(result3)) #将结果转换为列表格式 """ 利用lambda匿名函数调取字典中的age数据 用sorted自动将字典中的元素(列表)排序 """ dict1 = [{'name': 'Tom', 'age': 24}, {'name': 'Lily', 'age': 17},{'name': 'Jerry', 'age': 20},{'name': 'Golf', 'age': 7}] result4 = sorted(dict1, key=lambda x : x['age'], reverse=False) #对字典中age数据进行正序排列 print(result4)
递归函数条件:
自己调用自己、加判断作为终点(出口)、有初值(入口)
主要用于触发强制执行,例如页面需要登录才能进一步访问
def func1: def func2: pass return func2 @func1: def func3: pass func3工作原理:顺序定义 调用func3 找到func3所在装饰器func1 找到func1 执行func1下属的所有函数和代码(包括func2)
而对于以下代码
@decorate1 def func: pass @decorate2 def func: pass func多次装饰器,采用就近优先的原则,执行decorate2
装饰器sh:登录付款系统
""" 登陆状态判断,以及强行跳转,采用装饰器 需要强行跳转的函数,在其定义前使用装饰器@函数名 此处是在付款函数的定义前加登陆验证判断 装饰器是将函数作为参数,传入装饰器函数中,相当于调用被装饰函数=调用装饰器内部所定义的函数 """ import time #导入时间库 islogin = False #登陆状态,默认未登陆 #登陆界面 def login(): username = input('输入用户名:') password = input('输入密码:') if username == 'admin' and password == '123456': #用户名、密码核对正确,更改登录状态为True return True else: return False #验证付款登陆(装饰器) def login_required(func): def wrapper(*args,**kwargs): #wrapper的参数格式可变 global islogin #后面会更改全局变量islogin的值,需要声明 print('------------付款---------------') #验证登陆 if islogin: #若登陆成功,执行func,即执行pay func(*args,**kwargs) else: #若未登陆,进入login print('用户未登陆,不能付款') islogin=login() print('result:',islogin) return wrapper#表示func=wrapper,即pay=wrapper #验证付款 @login_required #调用付款函数前需要验证,类似于login_required(pay) def pay(money): print(f'正在付款,付款金额为:{money}') print('付款中。。。') time.sleep(2)#延时2s print('付款完成') #付款操作 while True: pay(input('输入付款金额'))#只有登录状态,才能执行付款
time
时间datetime日期、时间calendar日历hashlib加密算法copy拷贝functools常用工具os操作系统接口re字符串正则syspython自身的运行环境multiprocessing多进程threading多线程json编码和解码 json对象login记录日志、调试例如,生成随机验证码:
#验证码生成,包含大写字母和数字 def func(): code='' for i in range(4): ran1 = str(random.randint(0,9)) #随机数字 ran2 = chr(random.randint(65,90)) #随机大写字母(对应ASCII码) ran3 = chr(random.randint(97,122)) #随机小写字母 r = random.choice([ran1,ran2,ran3]) #随机选择数字、大小写字母 code += r #组成四位随机字符串 return code code1 = func() print(code1)
加密应用项目:
#密码加密举例 password = '123456' #设置密码 list2 = [] password_sha256 = hashlib.sha256(password.encode('utf-8')) #对密码进行编码、sha256加密 list2.append(password_sha256.hexdigest()) #将加密后的密码添加至密码列表中 pwd = input('输入密码:') #用户输入 pwd_sha256 = hashlib.sha256(pwd.encode('utf-8')) #对输入信息进行编码、sha256加密 pwd=password_sha256.hexdigest() #将加密后的用户输入,用16进制表示 print(pwd) for i in list2: #遍历密码列表,若加密后的用户输入和密码列表能对应,则登陆成功 if pwd == i: print('登陆成功')
python进行文件的读取写入操作需要借助数据流,相当于创建一个中间级,将数据以暂存的方式传输
with open('文件路径',mode='mode') as stream: 文件操作文件操作
文件路径包括 绝对路径和相对路径
绝对路径:从硬盘开始,到文件名
相对路径:同级直接写文件名,上级加 ../ ,下级加 /
模式mode包括:
r 纯文本文件读取
w 纯文本文件写入,会清空原有记录
rb 二进制读取,支持文本、图片、音乐、视频等
wb 二进制写入,支持文本、图片、音乐、视频等,会清空原有记录
a 添加,不清空原有记录
x 新建,文件已存在会报错
文件操作包括:
#读操作 open(path/filename,'r') #创建读取流,返回stream(流) stream.read() #读取信息 stream.readable() #是否可读 stream.readline() #读取一行 stream.readlines() #按行读取,返回列表 #写操作 open(path/filename,'w') #创建写入流,返回stream(流) stream.write() #写入信息 stream.writeline() #写入行 stream.writelines([]) #依次写入列表中的元素 #添操作 open(path/filename,'a') #创建添加流,返回stream(流) stream.write() #写入信息 stream.writelines([]) #依次写入列表中的元素 #新建操作 open(path/filename,'x') #创建新建&写入流,若已存在会报错 #关闭流,释放内存 stream.close()文件复制:
# 单个文件复制 with open('文件路径','rb') as stream1: 变量 = stream1.read() with open('新文件路径','wb') as stream2: stream.write(变量) #文件夹下所有文件复制 import os#导入os库 def copyfiles(src,target) #(封装函数) if os.path.isdir(src) and os.path.isdir(target): #判断src和target是否为有效路径 filelist = os.listdir(src) for file in filelist: #遍历src路径下所有文件 path = os.path.join(src,file) #将文件夹和文件名组合成绝对路径 with open(path,'rb') as stream1: #复制操作,将所有文件复制至target路径 container = stream1.read() path1 = os.path.join(target,file) with open(target,'wb') as stream2: stream2.write(container) else: #结束复制 print('复制完毕')文件路径相关
stream.name() #流所对应的路径 file.rfind('str') #文件路径(字符串)从右开始,str首次出现的位置 file.lfind('str') #文件路径(字符串)从左开始,str首次出现的位置 file[file.rfind('\\')+1:] #file文件名 import os #os模块(operatesystem操作系统,往往与路径相关) os.path.join(path,'str') #将已有路径后加上str部分 os.path.isabs(path) #判断是否是绝对路径 os.path.isdir(path) #判断是否是文件夹 os.path.dirname(__file__) #当前文件所在文件夹的路径 os.path.abspath(path) #相对路径转换为绝对路径 os.path.split(path) #得到元组(文件夹路径,文件名)切割出文件名 os.path.splitext(path) #得到元组(文件路径,文件类型)切割出文件扩展名 os.path.getsize(path) #获取文件大小,单位字节 os.path.exists(path) #判断文件是否存在 os.getcwd() #当前文件所在文件夹的路径 os.listdir(path) #返回目录中所有文件和文件夹名字列表 os.mkdir(path) #路径下创建文件夹(已有文件会报错) os.rmdir(path) #移除文件(只能删除空文件夹) os.removedirs(path) #移除目录下空文件 os.remove(path) #删除文件 os.chdir(path) #将当前文件路径更换至指定路径(进入指定目录)文件操作小项目1:
需要创建对应的 user.txt
""" 注册登录系统: 用户登录,在用户信息储存文件中核对用户名和密码,判断是否正确 用户注册,成功注册后会将新用户信息写入用户信息储存文件 """ def register(): username = input('输入用户名:') password = input('输入密码:') repassword = input('再次输入密码') if password == repassword: with open(r'C:\path\user.txt','a') as wstream: wstream.write('{}{}\n'.format(username,password)) print('注册成功') login() else: print('注册失败,请重新注册') return register() def login(): username = input('请输入用户名') password = input('请输入密码') input_info = '{}{}\n'.format(username,password) if username and password: with open(r'C:\new_path\user.txt','r') as rstream: user_infos = rstream.readlines() if input_info in user_infos: print('登录成功') else: print('用户名或密码错误') choise = input('1、重新登录2、注册') if choise == '2': register() else: return login() login()文件操作小项目2:
复制文件夹内所有内容,包括图片、文本、内部文件夹
import os def cpfiles(src_path,target_path): filelist = os.listdir(src_path) #获取文件夹内的文件,得到文件列表 for file in filelist: #遍历文件列表 path=os.path.join(src_path,file) #拼接路劲 if os.path.isdir(path): #判断是否为文件夹 nfile_path = os.path.join(target_path,file) #拼接路径 os.mkdir(nfile_path) #创建新文件夹 cpfiles(path,nfile_path) #对文件夹内容,递归 else: #不是文件夹,复制 with open(path,'rb') as rstream: #创建读取流 container = rstream.read() #读取内容 target_file = os.path.join(target_path,file) #拼接路径 with open(target_file,'wb') as wstream: #创建写入流 wstream.write(container) #粘贴内容 else: #遍历完成,复制完成 print('复制完成') cpfiles(r'C:\path\file_test', r'C:\path\copy_test')
try用于进行代码尝试,针对可能报错的代码,进行尝试执行,如果报错,进行预设处理,不会让代码停下,而是继续执行
try: 可能出现异常的代码 return 1 except error1 as err: #异常1时获取异常说明err 异常1时执行的代码 print(err) except error2: 异常2时执行的代码 return 2 else: 无异常时执行的代码 finally: 无论是否异常都会执行的代码 return 3 #会覆盖前值,返回3代码报错会优先父辈,为了便于排查错误,对于except对应的错误,按辈分从低到高顺序排列,最泛泛的error放在最后
自定义函数时,可通过自定义异常条件及异常说明,便于调用时进行错误提示和进行try操作
def register(): username = input('输入用户名:') if len(username) < 6: raise Exception('用户名长度必须6位以上') #抛出异常与异常说明 else: print('输入的用户名是:',username) try: register() except Exception as err: #运行异常,获取异常说明 print(err) print('注册失败') else: print('注册成功')
类: 将具有公共属性及方法的变量定义为类
类属性: 类自身固有的性质、变量及默认值,以及不可修改值
对象属性:定义在类中的属性,每个对象拥有不同属性值
类方法: 定义在类中的函数,参数为cls,调用时用 对象.方法,可用于修改不可修改类属性
@classmethod def 方法名(cls,[参数]): 内容 类名.方法名() 对象.方法名()对象方法:定义在类中的函数,参数为self,调用时用 对象.方法(变量值),不可调用类方法,不改变类属性默认值
魔术方法:触发自动执行
init 动态定义所有属性变量,并用传入的值赋于变量,
new 优先执行,开辟一块内存存储类,返回值作为self
call 让对象可作为函数调用,内容为call下代码
del 删除相同对象的引用(一般不用)
str 调用对象可以给出对象信息
静态方法: 无需传参,只能访问类方法和类属性,无法访问对象
@staticmethod def 方法名(): 内容 类名.方法名() 对象.方法名()类之间关系(继承): is a 与 has a
类属性或方法的共有
class Person: #定义类:人 def __init__(self,name): #定义对象初始属性(人共有) self.name = name self.age = 18 def eat(self): #定义方法(人共有) print(self.name+'正在吃饭') class Student(Person): #定义类:学生,继承父类Person def __init__(self,name,major): #定义对象初始属性 super().__init__(name) #子类定义init时必须包括定义父辈init self.major=major #Student独有属性 print('--------->Student的init') def study(self,course): #定义方法 print('{}正在学习{}课程'.format(self.name,course)) stu = Student('Jack','computer') #创建对象 stu.eat() #执行方法,方法来自Person继承 stu.study('python基础')在继承关系中,往往有 广度优先和深度优先 两大类
当存在多级继承的情况时,python采用广度优先的新式类
""" 多继承的优先级顺序问题 python3采用新式类:广度优先 """ class P1: def foo(self): print('------->P1_foo') def bar(self): print('------->p1_bar') class P2: def foo(self): print('------->p2_foo') class C1(P1,P2): pass class C2(P1,P2): def bar(self): print('------->c2_bar') class D(C1,C2): pass print(D.__mro__) #查看搜索顺序 d=D() d.foo() d.bar()
类属性的私有化,类外无访问权限
""" 封装:将某些属性私有化,类外无法访问 通过装饰器来授予权限 """ class Student: def __init__(self,age): self.__age=age #属性私有,外界无权访问 @property #允许外界取出属性 def age(self): return self.__age @age.setter #为age加装饰器,防止同名方法就近调用 def age(self,age): #允许外界修改属性 self.__age = age s = Student(50) print(s.age) s.age = 10 print(s.age)
类下共有
属于同一个类的不同对象,可以拥有自身独有的属性
""" 多态:通过加判断来限制动作对象,只有子类才能执行方法,否则不能执行 """ class Person: def __init__(self,name): self.name = name def feed_pet(self,pet): #接受传参 if isinstance(pet,Pet): #判断是否是子类 print('{}喜欢养宠物:{},昵称是{}'.format(self.name,pet.role,pet.nickname)) else: print('不是宠物,不能养') class Pet: role = '宠物' def __init__(self,nickname,age): self.nickname = nickname self.age = age def show(self): print('昵称:{},年龄:{}'.format(self.nickname,self.age)) class Cat(Pet): #定义宠物子类,猫 role = '猫' def catch_mouse(self): print('抓老鼠。。。') class Dog(Pet): #定义宠物子类,狗 role = '狗' def watch_house(self): print('看门。。。') class Tigger: #定义无关类,老虎 role = '大老虎' def eat(self): print('太可怕了,能吃人') cat = Cat('花花',2) #创建各类对象 dog = Dog('大黄',4) tigger = Tigger() person = Person('张伟') person.feed_pet(cat) #子类执行方法 person.feed_pet(tigger) #非子类执行方法
模块就是具有一定功能的py文件
包就是存储纯py文件的文件夹,必须包括 __init__.py 和 各模块.py
导入模块:
1.import 模块名
模块名.变量/函数/类
2.from 模块名 import 变量/函数/类, ....
在代码中可以直接使用变量,函数,类
3.from 模块名 import *
导入该模块中所有的内容 但是如果想限制获取的内容,可以在自定义模块中使用__all__=[*允许访问的内容, ...]
4.无论是import还是from的形式,都会将模块内的所有内容加载
如果不希望其进行内部语句调用,可在自定义模块中加入:
def test():... /定义模块中的函数
func /导入模块必定执行
if func == '__main__': /当且仅当本py文件运行时执行test函数,若本py文件被调用执行,则不执行test函数
test() 在自己的模块里面__name__叫:__main__
在其他模块中通过导入的方式调用时,__name__叫;__模块名__
__init__.py文件:
当导入包的时候,默认调用__init__.py文件
作用:
1.当导入包的时候,把一些初始化的函数,变量,类定义在__init__.py文件中
2.此文件中函数,变量等的访问,只需要通过包名.函数. ...
3.结合__all__=[通过*可以访问的模块]
循环导入的情况: 模块A: from B import funcB def funcA: 模块B: from A import funcA def funcB: 模块之间相互导入,发生错误 解决方法: 1.重新架构 2.将导入的语句放入函数里面 3.将导入语句放到模块的最后
并发:将独立CPU运行时间拆分为若干个时间段,并将他们分配给各线程执行 并行:每一个CPU执行一个线程,两个线程互不抢占CPU资源,可以同时进行 进程:程序对于某数据集合的一次运行活动,稳定性高(一个进程崩溃,不影响其他进程)无先后执行顺序,以同时进行为目的 线程: 进程与线程:进程是分配空间,线程是分配时间 cpu包括多进程,进程包括多线程 进程往往完成计算密集型操作 线程往往完成耗时较长的任务,避免长期占用内存 协程适用于耗时操作,例如网络请求、IO操作,协程的目的在于高效利用CPU 实现多任务的方式: 1、多进程模式:平行进程争夺CPU空间 2、多线程模式:平行线程争夺进程所有空间 3、协程:微线程 进程 》线程 》协程
from multiprocessing import Process
Process(target= 函数, name= 进程的名字, args= 给函数传递的参数)
process.start() 启动进程
process.run() 执行任务但不启动进程
process.terminate() 终止
#进程 #linux系统采用folk创建进程 #windows系统采用multiprocessing创建进程 import os from multiprocessing import Process from time import sleep sleep_num = 0 #声明全局变量,观察结果(全局变量在平行进程中相互独立,互不影响,不共用) #(全局变量在平行线程中共用,都可对变量进行调用处理) def task1(): global sleep_num while True: sleep(1) sleep_num += 1 print('这是子进程1',os.getpid(),'这是主进程',os.getppid(),'进程1沉睡次数=',sleep_num) def task2(second,name): global sleep_num while True: sleep(second) sleep_num += 1 print('这是子进程2',os.getpid(),'这是主进程',os.getppid(),'进程2沉睡次数=',sleep_num,name) def task3(second): while True: print(f'thisisprocess3,pleasewaitingfor{second}s') sleep(second) print('这是进程3') if __name__ == '__main__': #主进程开始 print('---------start----------') print(os.getppid()) #打印主进程pid p1 = Process(target=task1,name='任务1') #创建任务1为进程,task加()表示返回值,不加括号表示函数本身,此处不能加() p1.start() #启动进程 p2 = Process(target=task2,name='任务2',args=(2,'名字是任务2')) #进程传参:args=元组或列表 p2.start() p3 = Process(target=task3,name='任务3',args=(3,)) p3.start() print(p1.name) #打印进程1的名字 number = 0 while True: number += 1 sleep(0.1) if number == 30: #结束进程 p1.terminate() p2.terminate() print('进程1、2结束') elif number == 70: p3.terminate() break else: print('number=',number) #用于观察进程运行状况
将进程定义为类
""" 自定义进程: 通过创建类,自定义进程的参数、内容等 通过类,创建具有相同功能的进程 """ from multiprocessing import Process from time import sleep class MyProcess(Process): #把自定义进程,定义为一个类 def __init__(self,name): #通过__init__添加参数name super(MyProcess,self).__init__() self.name = name def run(self): #进程运行的内容,打印并延时0.5s n=1 while True: print('自定义进程名字为{},n={}'.format(self.name,n)) n+=1 sleep(0.5) i=0 if __name__ == '__main__':#主程序(主进程) p1 = MyProcess('进程1') #按自定义进程类,创建进程 p2 = MyProcess('进程2') p1.start() #启动进程 p2.start() while True: if i == 3: #当3s后结束进程 p1.terminate() p2.terminate() break sleep(1) #按秒判断 i+=1
线程状态: 新建---(start)--->就绪--->运行---(此处若阻塞,即sleep,则让出进程空间,返回就绪状态)--->结束 import threading threading.Thread(target= , name= ) th.start() th.join()
当共享数据时,由于线程运行过程中可能存在阻塞,导致抢行,产生数据不安全 全局解释器锁GIL(global interpreter lock):线程同步,保护执行中的线程,防止线程抢行导致的数据不同步,但是会牺牲运行速度
#线程: import threading import time lock = threading.Lock() #创建锁 list1 = [0]*10 def task1(): #获取线程锁,如果锁被占用,则等待锁的释放 lock.acquire() #阻塞 for i in range(len(list1)): #共享数据的处理放在acquire与release之间 list1[i]=i time.sleep(0.5) lock.release() #释放锁,如果不释放,其他线程无法进入执行状态 def task2(): lock.acquire() for i in range(len(list1)): print(i) time.sleep(0.5) lock.release() if __name__ == '__main__': t1 = threading.Thread(target=task1) t2 = threading.Thread(target=task2) t1.start() t2.start() print(threading.current_thread()) #当前正在执行的线程 print(threading.enumerate()) #所有执行及等待中的线程列表 t1.join() #提高一级优先级,优先执行 t2.join() #t1,t2相同优先级,高于main print(list1)
死锁:两个线程的执行过程中需要相互调用各自的锁,则线程1占据进程并等待锁2,而锁2的释放需要占据进程,但此时需要等待线程1释放 解决方法:
1、重构代码 2、acquire(timeout= )设置占据时间上限,等待过长则自动释放 release
#死锁 from threading import Thread,Lock import time lockA = Lock() lockB = Lock() class MyThread1(Thread): def run(self): if lockA.acquire(): print(self.name+'获取了A锁') time.sleep(0.1) if lockB.acquire(): print(self.name+'又获取了B锁,原来还有A锁') lockB.release() lockA.release() class MyThread2(Thread): def run(self): if lockB.acquire(): print(self.name+'获取了B锁') time.sleep(0.1) if lockA.acquire(): print(self.name+'又获取了A锁,原来还有B锁') lockA.release() lockB.release() if __name__ == '__main__': th1 = MyThread1() th2 = MyThread2() th1.start() th2.start()
生产者与消费者:两个线程之间的通信 不一定生产一个吃一个,属于抢夺行为
1、通过加锁保证数据安全
#生产者与消费者Lock版 import random import threading import time Money = 10000 Lock = threading.Lock() Time = 0 class Producer(threading.Thread): def run(self): global Money global Time while True: produce = random.randint(500,1000) Lock.acquire() if Time >= 10: Lock.release() break else: Money += produce print('生产者%s生产了%d元钱,总共%d元钱'%(threading.current_thread(),produce,Money)) Time+=1 Lock.release() time.sleep(0.5) class Consumer(threading.Thread): def run(self): global Money while True: consume = random.randint(1,2000) Lock.acquire() if Money < consume and threading.Thread.is_alive(th) != True: print('消费者%s准备消费%d元钱,但是只剩%d元钱,钱不够'%(threading.current_thread(),consume,Money)) Lock.release() break else: Money -= consume print('消费者%s消费了%d元钱,还剩%d元钱'%(threading.current_thread(),consume,Money)) Lock.release() time.sleep(0.5) if __name__ == '__main__': th = Producer(name='生产者%d'%Time) th.start() tc = Consumer(name='消费者') tc.start() print(threading.Thread.is_alive(th)) while True: if threading.active_count() == 1: print('='*30+'end'+'='*30) break
2、通过condition进行数据保护,线程待机等待唤醒的方式保证数据安全
#生产者和消费者condition版线程待机等待唤醒 import random import threading import time Money = 10000 Condition = threading.Condition() Time = 0 class Producer(threading.Thread): def run(self): global Money global Time while True: produce = random.randint(500,1000) Condition.acquire() if Time >= 10: Condition.release() break else: Money += produce print('生产者%s生产了%d元钱,总共%d元钱'%(threading.current_thread(),produce,Money)) Time += 1 Condition.notify_all() #通知所有等待中的线程 Condition.release() time.sleep(0.5) class Consumer(threading.Thread): def run(self): global Money while True: consume = random.randint(1,2000) Condition.acquire() while Money < consume: print('消费者%s准备消费%d元钱,但是只剩%d元钱,钱不够'%(threading.current_thread(),consume,Money)) if not threading.Thread.is_alive(th): Condition.release() return #跳出所有循环 Condition.wait() #等待 Money -= consume print('消费者%s消费了%d元钱,还剩%d元钱'%(threading.current_thread(),consume,Money)) Condition.release() time.sleep(0.5) if __name__ == '__main__': th = Producer(name='生产者%d'%Time) th.start() tc = Consumer(name='消费者') tc.start() print(threading.Thread.is_alive(th)) #判断th线程是否处于有效状态 while True: if threading.active_count() == 1: #除主线程外无其他有效线程 print('='*30+'end'+'='*30) break
3、设置中间介queue队列,保证数据安全
FIFO:先入后出队列
LIFO:先出后入队列
队列与堆栈取出数据的顺序相反,队列通常是先入先出,堆栈则是后入先出
#生产者和消费者Queue版线程安全队列 #队列等于排队,先到先得,先进入队列的会先被取走 #堆栈等于叠碟,后到先走,后进入堆栈的会先被取走 import threading from queue import Queue import time import random Time = 0 Condition = threading.Condition() fruits = ['苹果','梨子','香蕉','荔枝','西瓜','榴莲','桃子'] def Producer(q): global Time while True: produce = random.choice(fruits) Condition.acquire() if Time >= 10: Condition.notify_all() #通知所有等待中的线程 Condition.release() break else: q.put(produce) print('生产者%s生产了%s'%(threading.current_thread(),produce)) Time += 1 Condition.notify_all() #通知所有等待中的线程 Condition.release() time.sleep(random.random()) def Consumer(q): while True: Condition.acquire() while q.empty(): print('消费者%s准备吃水果,但是没有了'%(threading.current_thread())) if not threading.Thread.is_alive(tp): Condition.release() return #跳出所有循环 Condition.wait()#等待 consume = q.get() print('消费者%s吃了%s,还剩%d个水果'%(threading.current_thread(),consume,q.qsize())) Condition.release() time.sleep(0.7) q = Queue(10) tp = threading.Thread(target=Producer,args=(q,)) tc = threading.Thread(target=Consumer,args=(q,)) tp.start() tc.start() while True: if threading.active_count() == 1: print('='*30+'end'+'='*30) break
greenlet版
#协程 pip install greenlet import time from greenlet import greenlet def taskA(): for i in range(5): print('A',i) gb.switch() #阻塞前启动协程b,释放空间 time.sleep(0.5) def taskB(): for i inrange(5): print('B',i) gc.switch() #阻塞前启动协程c,释放空间 time.sleep(0.5) def taskC(): for i in range(5): print('C',i) ga.switch() #阻塞前启动协程a,释放空间 time.sleep(0.5) if __name__ == '__main__': ga = greenlet(taskA) gb = greenlet(taskB) gc = greenlet(taskC) ga.switch() gb.switch() gc.switch()
gevent版
通过猴子补丁进行协程自动分配
#协程 pip install gevent 自动切换行程,不用等待IO import time import gevent from gevent import monkey monkey.patch_all() #猴子补丁:感知耗时操作,自动替换所有阻塞操作,让协程自动切换 def taskA(): for i in range(5): print('A',i) time.sleep(0.5) def taskB(): for i in range(5): print('B',i) time.sleep(0.5) def taskC(): for i in range(5): print('C',i) time.sleep(0.5) if __name__ == '__main__': ga = gevent.spawn(taskA) gb = gevent.spawn(taskB) gc = gevent.spawn(taskC) ga.join() gb.join() gc.join()
正则表达式 Regular Expression。用于验证字符串的逻辑公式,简称re
特点: 给定一个正则表达式和另一个字符串,可以达到以下目的:
1、给定的字符串是否符合正则表达式的过滤逻辑(称为‘匹配’)
2、可以通过正则表达式,从字符串中获取我们想要的特定部分
re模块函数:
match从开头匹配一次search顺序查找,只匹配一次findall顺序查找全部,遍历所有sub按照 (正则, 新内容, 原内容) 进行替换split在正则处分割,返回剩余部分组成的列表
\A: 表示从字符串的开始处匹配 \Z: 表示从字符串的结束处匹配,如果存在换行,只匹配到换行前的结束字符串 \b: 匹配一个单词边界,也就是指单词和空格间的位置。例如,'py\b'可以匹配'python'中的'py',但不能匹配'openpyxl'中的'py' \B: 匹配非单词边界。'py\B'可以匹配'openpyxl'中的'py',但不能匹配'python'中的'py' \d: 匹配任意数字,等价于[0-9] digit \D: 匹配任意非数字字符,等价于[^\d] not digit \s: 匹配任意空白字符,等价于[\t\n\r\f] space \S: 匹配任意非空白字符,等价于[^\s] not space \w: 匹配任意字母数字及下划线,等价于[a-zA-Z0-9_] word \W: 匹配任意非字母数字及下划线,等价于[^\w] \: 转义,将后面的第一个字符取消其特殊意义 \\: 匹配原义的反斜杠\ . : 匹配除换行符(\n)以外的所有字符 ^: 匹配字符串的开始,即行首 中括号内表示取逻辑非,例如,[^0-9]等价于除了0-9以外的其他字符 $: 匹配字符串的末尾,(末尾如果有换行符\n,就匹配\n前面的那个字符),即行尾 *: 按前面的匹配模式,匹配0次或多次(贪婪模式,即尽可能多的匹配),>=0 (判断:不能出现其他内容) +: 按前面的匹配模式,匹配1次或多次(贪婪模式),>=1 (判断:必须出现) ?: 按前面的匹配模式,匹配0次或1次(贪婪模式),0,1 (判断:可有可无,查询:非贪婪,选择最短字符串) |: 或者,条件并列。小括号内表示整体或,例如,(abc|def)等价于abc或def 中括号内表示字符或,例如,[abc|def]等价于a、b、c、|、d、e或f {m}: 验证按前面的匹配模式,匹配m次 {m,}: 验证按前面的匹配模式,匹配m次或多次 >=m {m,n}: 验证按前面的匹配模式,匹配m次以上,n次以下 >=m,<=n 在*,?,+,{m,n}后面加?,转换为非贪婪,总是尝试匹配尽可能少的数据
正则表达式应用举例
import re msg1 = 'jack334c2#^2jerry2km*&' print(re.match(r'jack',msg1)) #match从头开始匹配,匹配成功则返回,否则返回None print(re.match(r'[0-9a-zA-Z_]{3,}',msg1)) #match从头开始匹配,由数字、字符或下划线组成,3位及以上 print(re.search(r'jerry',msg1)) #search顺序查找匹配 print(re.search(r'jerry',msg1).span()) #匹配成功位置 print(re.search(r'[a-z][0-9][a-z]',msg1).group()) #匹配成功的内容部分,首中即停 print(re.findall(r'[a-z][0-9]+[a-z]',msg1)) #匹配成功的内容部分,找完为止 print(re.search(r'^[a-zA-Z]\w{3,}$',msg1)) #search顺序查找匹配,从头开始到末尾,以字符开头,由数字、字符或下划线组成,4位及以上 msg2 = 'a*pyb.pycc.pyd.txtepython.txt' print(re.findall('\w*.py\\b',msg2)) #find查找所有,数字字符下划线+除换行符以外任意字符+py,且满足单词边界的字符串 #无r开头,加\表示\b不是字符格式,而是正则格式 print(re.findall(r'\w*\.py\b',msg2)) #find查找所有,数字字符下划线+.+py,且满足单词边界的字符串 #有r开头,加入\表示.不是正则格式(任意非换行字符),而是.字符 print(re.sub(r'py\b','txt',msg2)) #按正则替换 #0-100数字正则 text = '100' print(re.match(r'\d?\d$|^100$',text)) #手机号码正则 phone = input('请输入电话号码') if re.match('1[35789]\d{9}$',phone) != None: print('输入成功') else: print('号码错误') #邮箱正则 email = '123456789@qq.com' print(re.match(r'\w{5,20}@(126|163|qq)\.(com|cn)$',email)) #URL正则 url = 'http://www,hao123.com' print(re.match(r'(ftp|http|https)://\S+',url)) #爬虫正则 msg3 = '<html><h1>abc</h1></html>' print(re.match(r'<(?P<name1>\w+)><(?P<name2>\w+)>(.+)</(?P=name2)></(?P=name1)>',msg3)) #用起名的方式进行重复项正则,(?P<名字>正则)...(?P=名字) result1 = re.match(r'<(\w+)><(\w+)>(.+)</(\2)></(\1)>',msg3) #进行分组,个别组的数据相同,后组引用前组内容 print(re.sub(r'<.+?>','',msg3)) print(result1) print(result1.group(3)) #提取分组中第三组的数据,若索引为0表示返回整个数据 print(result1.group(1,2)) print(result1.groups()) #菜品涨价 def price_change(price): #菜品价格低于10元,则涨价1元 num = int(price.group()) if num < 10: num += 1 return str(num) pricelist = '白菜5元,香菇9元,上海青12元' print(re.sub(r'\d+',price_change,pricelist)) #对菜品价格正则替换 print(re.split(r'\d+元,?',pricelist)) #正则剪切出菜品名 result2 = re.findall(r',?(\D+)(\d+)元',pricelist) #利用()进行分组得到元组,利用元组获得菜品列表 print([i[0] for i in result2]) msg4 = 'thenumberis20.50' r = re.compile(r"""\d+ #小数点前数字 \.? #小数点 \d* #小数点后面的数字 """,re.VERBOSE) #匹配格式,VERBOSE可以在后面注释 result3 = re.search(r,msg4) #按照r的格式对msg4进行匹配 print(result3.group())