目录
第八章 多任务
多任务的最大好处是充分利用CPU资源,提高程序的执行效率
多任务的执行方式:
并发:在一段时间内交替去执行多个任务
并行:在一段时间内真正的同时一起执行多个任务
1 多任务编程
1.1 进程
进程是操作系统进行资源分配的基本单位,也就是说每启动一个进程,操作系统都会给其分配一定的运行资源(内存资源)保证进程的运行。
进程与进程之间是不共享资源的,互不影响
线程与线程之间会共享资源,会相互影响
线程是依附在线程之间的
Process进程类的说明
# 1. 导入进程包
import multiprocessing
# 2. 通过进程类创建进程对象
进程对象 = multiprocessing.Process()
# 3. 启动进程执行任务
进程对象.start()
Process进程常用方法:
函数名 | 含义 |
---|---|
Process(target = None, name = None, *args, **kwargs) | 用于创建进程对象。其中,参数target表示任务函数,其他参数内容建议都采用键值对形式传值。 |
start() | 启动进程,并执行任务。 |
join() | 等待某进程优先执行,可理解为:插队。 |
# 1.导入包
import time
from multiprocessing import Process
# 定义唱歌方法
def sing():
for temp in range(5):
print(f"============唱歌中。。================={temp}")
time.sleep(1)
# 定义跳舞方法
def dance():
for index in range(5):
print(f"{index}==============跳舞中================")
if __name__=='__main__':
# 3.创建进程
sing_process=Process(target=sing)
dance_process=Process(target=dance)
# 4.启动进程
sing_process.start() # 更稳定;插入
dance_process.start()
sing_process.join()
1.2 线程
使用步骤:
1:导入线程模块, import threading
或者from threading import Thread
2:创建线程对象, 对象名 = threading.Thread(target=xxx,...)
3:启动线程, 对象名.start()
导包的两种方法
# 方法1
import threading # 推荐
threading.Thread()
# 方法2
from threading import Thread
Thread()
Thread线程常用方法:
函数名 | 含义 |
---|---|
Thread(target = None, name = None, *args, **kwargs) | 用于创建线程对象。其中,参数target表示任务函数,其他参数内容建议都采用键值对形式传值。 |
start() | 启动线程,并执行任务。 |
join() | 等待某线程优先执行,可理解为:插队。 |
# 1.导出包
import threading
import time
# 2.定义方法
def dance():
for temp in range(5):
print("===========跳舞中。。。===================")
time.sleep(1)
def sing():
for index in range(5):
print("***************唱歌中******************")
time.sleep(1)
if __name__=="__main__":
# 3.创建线程对象
dance_thread=threading.Thread(target=dance)
# 4.启动线程
dance_thread.start()
sing_thread=threading.Thread(target=sing)
sing_thread.start()
1:可以使用线程来完成多任务;
2:线程与线程之间是会互抢内存资源的;
3:使用多线程来完成多任务的效果更加贴近同步执行.
# ---------------------04 可变类型的全局变量------------------------
import threading
# 全局变量
datas=[1,2,3,4]
# 1.任务1
def func():
global datas #声明全局变量
datas.append(1000) #对于修改可变类型的全局变量:也可以不加global声明
print(f"子线程A获取数据结果:{datas}")
# 2.任务2
def task():
print(f"===========字线程B结果:{datas}")
# 3.判断
if __name__=="__main__":
thread_a=threading.Thread(target=func)
thread_a.start()
thread_b=threading.Thread(target=task)
thread_b.start()
2 浅拷贝与深拷贝
浅拷贝:对于可变的数据类型(如列表、字典等),浅拷贝会复制对象,但是不会复制对象内部的数据。浅拷贝会创建一个新的对象,但是这个对象中的数据仍然使用原始对象中的引用。如果原始对象的某个属性发生了变化,浅拷贝对象中对应的属性也会发生变化。
copy(t):使用浅拷贝来拷贝信息,拷贝父对象,不会拷贝对象的内部的子对象。
import copy
# 1.不可变类型
a=19
ret1=copy.copy(a)
# 值相同
print(a) # 19
print(ret1) # 19
# 内存地址相同
print(id(a)) # 140733489780960
print(id(ret1)) # 140733489780960
# 2.可变类型
b=[10,20,30]
ret2=copy.copy(b)
# 值相同
print(b) # [10, 20, 30]
print(ret2) # [10, 20, 30]
# id地址不同
print(id(a)) # 140733489780960
print(id(ret2)) # 140733489780960
深拷贝:深拷贝会复制对象及其内部的所有数据,包括子对象等。深拷贝会创建一个与原始对象完全独立的新对象,即使原始对象的某个属性发生了变化,深拷贝对象对应的属性也不会发生改变。
deepcopy(t):使用深拷贝来拷贝信息,完全拷贝了父对象及其子对象。
import copy
# 不可变类型
m="hello"
result1=copy.deepcopy(m)
# 值相同
print(m) # hello
print(result1) # hello
# 内存地址值相同
print(id(m)) # 1563619028528
print(id(result1)) # 1563619028528
# 可变类型
n=[10,20,30]
result2=copy.deepcopy(n)
# 值相同
print(n) # [10, 20, 30]
print(result2) # [10, 20, 30]
# 内存地址值不同
print(id(n)) # 1563620456128
print(id(result2)) # 1563620456960
区别:
深拷贝是对父子对象的所有内容都进行值和内存地址值的拷贝;
浅拷贝仅对父对象进行了拷贝,而没有对子对象进行拷贝处理;
当拷贝多层数据时,才能发现深浅拷贝是否对子对象进行拷贝处理
import copy
m=[1,2,3]
n=[10,20]
datas=[m,n]
print("==========浅拷贝=========")
result1=copy.copy(datas)
print(datas) # [[1, 2, 3], [10, 20]]
print(result1) # [[1, 2, 3], [10, 20]]
# 修改m
m.append(1000)
print(datas) # [[1, 2, 3, 1000], [10, 20]]
print(result1) # [[1, 2, 3, 1000], [10, 20]]
# 值一致,内部数据指向同一个内存,m没有重新开辟空间
print("==========深拷贝=========")
result2=copy.deepcopy(datas)
m.append(99)
print(datas) # [[1, 2, 3, 1000, 99], [10, 20]]
print(result2) # [[1, 2, 3, 1000], [10, 20]]
3 闭包
作用:保存函数内的变量,而不会随着调用完函数而被销毁
定义语法:
# 外部函数
def 外部函数名(外部参数):
# 内部函数
def 内部函数名(内部参数):
...[使用]
代码
return 内部函数名 # 闭包
调用闭包语法:
变量名 = 外部函数名([外部参数列表])
变量名([内部参数列表])
要构成闭包,需要满足3个条件:
(1)有嵌套:外部函数中嵌套了一个内部函数
(2)有引用:内部函数中使用了外部函数的变量或参数
(3)有返回:需要把内部函数名返回给外部函数
# 1.定义闭包
def outer(x):
def inner(y):
result=x+y
print(f"两数之和为:{result}")
return inner
# 2.调用闭包 # outer()==>外部函数outer()
get_sum=outer(80)
get_sum(30)
get_sum(80)
结果如下:
两数之和为:110
两数之和为:160
nonlocal关键字
在闭包的使用过程中,当要在内部函数中修改外部函数的变量,需要使用nonlocal提前声明。
# 1.定义闭包
def outer():
a=100
def inner():
print("=====================")
nonlocal a
a+=1
print(f"修改后的结果:{a}")
print("=====================")
return inner
# 调用使用
result=outer()
print(result)
result()
# 也等同于以下方法
outer()() # 调用函数要加括号
4 装饰器
装饰器其实就是特殊的闭包
要构成装饰器,需要满足4个条件:
(1) 有嵌套:外部函数中嵌套了一个内部函数
(2) 有引用:内部函数中使用了外部函数的变量或参数
(3) 有返回:需要把内部函数名返回给外部函数
(4) 有额外功能:在不修改原有函数基础上,增加额外功能
定义语法:
def outer([外面参数列表]):
def inner([内部参数列表]):
新增额外功能代码
....
...[引用]
return inner
使用装饰器的标准语法
@outer
def 函数名():
代码
...
def outer(func):
def inner(): # 有嵌套
print("发表评论前记得先登录") # 有额外功能
func() # 有引用 -->调用函数:加()
return inner # 有返回
# 2.使用装饰器
# 3.定义函数
@outer
def publish():
print("可以发表你的评论了...")
# 调用函数
publish()
结果如下:
发表评论前记得先登录
可以发表你的评论了...
1 装饰无参无返回值的函数
# 1.定义装饰器
def outer(func):
def inner(): # 有嵌套
print("==========正在努力计算中===========") # 有额外功能
func() # 有引用
return inner # 有返回
# 2.使用装饰器
# 3.定义函数
@outer
def get_sum():
a=10
b=20
sum=a+b
print(f"两数之和为{sum}")
# 4.调用函数
get_sum()
2 装饰有参无返回值的函数
# 1.定义装饰器
def outer(func):
def inner(x,y): # 有嵌套
print("==========正在努力计算中===========") # 有额外功能
func(x,y) # 有引用
return inner # 有返回
# 2.使用装饰器
# 3.定义函数
@outer
def get_sum(a,b):
sum=a+b
print(f"两数之和为{sum}")
# 4.调用函数
get_sum(10,20)
3 装饰无参有返回值的函数
# 1.定义装饰器
def outer(func):
def inner(): # 有嵌套
print("==========正在努力计算中===========") # 有额外功能
result=func() # 有引用
return result
return inner # 有返回
# 2.使用装饰器
# 3.定义函数
@outer
def get_sum():
a=10
b=20
sum=a+b
return sum
# 4.调用函数
print(get_sum())
4 装饰有参有返回值的函数
# 1.定义装饰器
def outer(func):
def inner(x,y): # 有嵌套
print("==========正在努力计算中===========") # 有额外功能
result=func(x,xxxxxxxxxxxccxy) # 有引用
return result
return inner # 有返回
# 2.使用装饰器
# 3.定义函数
@outer
def get_sum(a,b):
sum=a+b
return sum
# 4.调用函数
print(get_sum(10,20))
第九章 正则表达式
1 正则表达式的概述
Python正则表达式指的是符合一定规则的字符串,能用于检查一段文本数据是否与某种模式匹配(正则是特殊的字符串)
导入模块:# import re
re模块常用方法:
match(pattern, string):返回一个已匹配成功的对象。其中,参数pattern表示正则字符串,参数string表示要匹配的内容。
group(num=0):匹配成功的内容,num默认是0,表示匹配的所有数据结果。
当正则匹配不出结果时,就会为None,无法调用group0方法
import re
phone="13729371623"
# 2.匹配
regex="[1][0-9]{10}$" #只匹配11位
matcher=re.match(regex,phone)
# 3.判断
# if matcher != None:
if matcher is not None:
print("手机号码是合格!")
# 获取结果
result=matcher.group()
print(f"结果是{result}")
else:
print(f"{phone}不是标准格式的手机号码")
2 正则的常见规则
2.1 匹配单个字符!
匹配单个字符:只能匹配一个.
代码 | 功能 |
---|---|
. | 匹配除\n之外的任何单个字符。 |
[ ] | 匹配[ ]中列举的字符。 |
\d | 匹配一个数字字符,比如[0-9]。 |
\D | 匹配一个非数字字符,比如[^0-9] 。 |
\s | 匹配任何空白字符。 |
\S | 匹配任何非空白字符。 |
\w | 匹配非特殊字符,比如a-z、A-Z、0-9、_、汉字。 |
\W | 匹配特殊字符,比如非字母、非数字、非汉字等。 |
# 1.导入模块
import re
# 如果报错正则匹配有问题
# 2.任意字符
print(f"结果是{re.match('.','h').group()}")
print(f"结果是{re.match('.','1').group()}")
print(f"结果是{re.match('.','_').group()}")
print(f"结果是{re.match('.','python').group()}") # 只能匹配单个字符。结果是p
结果是h
结果是1
结果是_
结果是p
# 3.大小写、非数字
print(f"结果是{re.match('[a-z]','a').group()}")
print(f"结果是{re.match('[a-z]','y').group()}")
# print(f"结果是{re.match('[a-z]','Y').group()}") #报错 AttributeError: 'NoneType' object has no attribute 'group'
print(f"结果是{re.match('[a-z]','abc').group()}") # 结果是a
print(f"结果是{re.match('[A-Z]','B').group()}")
print(f"结果是{re.match('[0-9]','1').group()}")
print(f"结果是{re.match('[^0-9]','b').group()}")
print(re.match('\D','b').group())
# # 4.一个数字
print(f"结果是{re.match('[0-9]','8').group()}")
print(f"结果是{re.match('[0-9]','66').group()}") # 结果是6
print(re.match('\d','6').group())
# # 5.单字符,匹配非特殊字符,比如a-z、A-Z、0-9、_、汉字。
print(re.match('\w','6').group())
print(re.match('\w','a').group())
print(re.match('\w','N').group())
print(re.match('\w','_').group())
print(re.match('\w','中国').group()) # 结果是:中
2.2 原始字符串
原始字符串:在字符串前添加r表示字符串的原始含义。语法:r"正则表达式"
# 1.导入模块
import re
# 2.匹配
result=re.match("E:\\\\","E:\\").group() # E:\
# 3.原始字符串,程序报错了就在正则前添加r
# result=re.match("E:\\","E:\\").group() #报错
result=re.match(r"E:\\","E:\\").group() # E:\
# 4.输出结果
print(f"结果是{result}")
2.3 匹配多个字符!
常用的匹配多个字符的语法:
代码 | 功能 |
---|---|
X* | 匹配X出现0次或无限次,即可有可无。 |
X+ | 匹配X出现1次或无限次,即至少有1次。 |
X? | 匹配X出现1次或0次,即有一次或一次也没有。 |
X{m} | 匹配X恰好出现m次。 |
X{m,n} | 匹配X至少m次,但是不超过n次。 |
import re
# # X*
# result=re.match("[a-zA-Z][a-z]*","x").group()
# print(f"结果是{result}")
# # X+
# # result=re.match("\w","123abcABC_HELLO").group()
# result=re.match("\w+","123abcABC_HELLO").group()
# print(f"结果是{result}")
# X?
# result=re.match("[1-9][0-9]","98").group()
# result=re.match("[0-9]?[0-9]","0").group() #? 表前面可有可无
# result=re.match("[1-9]?[0-9]","09").group() # 结果是0,思维不严谨
# print(f"结果是{result}")
# X{m,n}
result=re.match("[a-zA-Z0-9_]{5,16}","1234_GHDY8").group() # 结果是0,思维不严谨
print(f"结果是{result}")
2.4 匹配开头和结尾
匹配开头和结尾语法:
代码 | 功能 |
---|---|
^ | 匹配字符串开头。 |
$ | 匹配字符串结尾。 |
import re
# 匹配开头:非数字
# X{m,n}
# result=re.match("[^0-9]","1").group() # 结果AttributeError: 'NoneType' object has no attribute 'group'
# result=re.match("[^0-9]","D").group()
# result=re.match("[^0-9]","hhh").group()
# result=re.match("[^0-9]+","hhh").group()
# print(f"结果是:{result}")
# 匹配结尾
result=re.match("www.baidu.com","www.baidu.com.edu").group()
# result=re.match("www.baidu.com$","www.baidu.com.edu").group() #加$限定结尾,不匹配则报错AttributeError: 'NoneType' object has no attribute 'group'
print(f"结果是:{result}")
2.5 匹配分组!
要获取分组数据信息,语法:
代码 | 功能 |
---|---|
X|Y | 匹配X或Y的任意一个表达式。 |
(X) | 将括号中字符X作为一个分组用于获取,且从1开始统计分组。 |
import re
# 数字
# # result=re.match("[1-9]?[0-9]|100","8").group()
# result=re.match("[1-9]?[0-9]|100","87").group()
# result=re.match("[1-9]?[0-9]|100","99").group()
# result=re.match("[1-9]?[0-9]|100","100").group() # 结果是10
# result=re.match("100|[1-9]?[0-9]","100").group() # 将100放到前面
result=re.match("100|[1-9]?[0-9]","10").group() # 结果是:10
print(f"结果是:{result}")
# 邮箱号 X{m,n}匹配X至少m次,但是不超过n次。
# result=re.match("\w{4,12}@(126|163|qq).com","hellopy@qq.com").group()
# result=re.match("\w{4,12}@(126|163|qq).com","hellopy@163.com").group(1) # 获取邮箱类型,第一个括号(126|163|qq)
# result=re.match("(\w{4,12})@(126|163|qq).com","hellopy@163.com").group(1) # 获取邮箱名称,第一个括号(\w{4,12})
# result=re.match("(\w{4,12})@(126|163|qq).com","hellopy@163.com").group(2) # 获取邮箱名称,第二个括号(126|163|qq)
result=re.match("\w{4,12}@(126|163|qq).com","hellopy@163.com").group(0) # 获取邮箱
print(f"结果是:{result}")
print(f"结果是:{result[:result.find('@')]}") # 获取用户名
3 Python与MySQL的交互
在Python中,使用pymysql模块来操作MySQL数据的基本步骤:
(1)导入模块;
(2)创建连接对象;
(3)创建游标对象;
(4)使用游标对象执行SQL并进行增删改查;
(5)关闭游标对象;
(6)关闭连接对象。
connection是用于建立与数据库的连接,需要使用pymysql模块来调用:
①host:连接MySQL的IP地址。本机可表示成’localhost’或’127.0.0.1’;其他计算机则表示为具体IP地址;
②port:连接的MySQL的端口号,默认是3306;
③user:连接的用户名,默认是root;
④password:连接的密码;
⑤database:数据库的名称;
⑥charset:采用的编码方式,设定为’utf8’即可。
当成功通过connect()获取并得到连接对象后,常用函数:
commit():用于事务提交,在进行数据操作时需要进行事务提交后才会生效。 [对数据结果会产生影响的代码才要提交。]
close():用于关闭连接。
rollback():用于事务回滚,放弃之前的所有操作,并回到开启事务前的状态。
cursor():用于返回Cursor对象,可使用该对象来执行SQL语句并获取结果。
特别注意:
(1)使用pymysql模块时,已默认开启了事务,因此要让数据操作生效,则必须要进行事务提交;
(2)为了节约系统内存资源,通常在使用完Connection连接对象后,要进行关闭连接。
Cursor对象
若要执行SQL语句时,则需要使用cursor对象,可通过connection对象的cursor()方法进行创建。
cursor():用于返回cursor对象,可使用该对象来执行SQL语句并获取结果。
当有了cursor对象后,常用函数:
函数 | 含义 |
---|---|
execute(operate [, param]) | 用于执行SQL语句,返回受影响的行数。 其中,参数operate为字符串类型,表示SQL语句; 参数parameters为列表类型,表示SQL语句中的参数。 |
fetchone() | 在执行查询语句时,获取查询结果集的第一行数据,返回一个元组,即(v1, v2,…)。 |
fetchall() | 在执行查询时,获取结果集的所有行,返回一个元组,即((v11, v12,…), (v21, v22,…),…)。 |
close() | 关闭cursor对象。 |
# 1.导入模块
import pymysql
# 2.创建连接对象
db_conn = pymysql.connect(host="localhost",
port=3306,
user="root",
password="123456",
database="bigdata2",
charset="utf8")
# 3.创建游标对象
db_cursor=db_conn.cursor()
# 4.编写SQL执行语句
# 增
sql1="insert into bigdata2.user(uid,uname,uemail) values(5,'hh','hhy@qq.com')"
db_cursor.execute(sql1)
# 删
sql2="delete from bigdata2.user where uname='yy'"
db_cursor.execute(sql2)
# 改
sql3="update bigdata2.user set uemail='777@qq.com' where uname='赵六'"
db_cursor.execute(sql3)
# 提交事务
db_conn.commit()
print("操作执行成功")
# 关闭游标
db_cursor.close()
# 关闭连接
db_conn.close()
遍历查看数据表
import pymysql
db_conn=pymysql.connect(
host="localhost",
port=3306,
user="root",
password="123456",
database="db_users",
charset="utf8"
)
db_cursor=db_conn.cursor()
sql="select * from db_users.tb_user"
# username=input("请输入用户名:")
# params=[username]
db_cursor.execute(sql)
# result=db_cursor.fetchone()
result=db_cursor.fetchall()
print(f"查询一条结果:{result}")
for id,username,password in result:
print(id,username,password)
db_conn.commit()
db_cursor.close()
db_conn.close()
print("数据查询已完成")
sql注入
SQL注入指的是:恶意篡改或注入SQL条件。
当开发者的数据条件若被恶意篡改,那就达不到预期的查询效果。
如select * from bigdata2.user where uemail='yyy@qq.com';
在查询语句后加一个结果为True的条件即可查出表中所有数据
select * from bigdata2.user where uemail='yyy@qq.com' or 1=1;
解决方法:在pymysql模块中,可采用语句参数化来解决
# 1.导入模块
import pymysql
# 2.创建连接对象
db_conn = pymysql.connect(host="localhost",
port=3306,
user="root",
password="123456",
database="bigdata2",
charset="utf8")
# 3.创建游标对象
db_cursor=db_conn.cursor()
# 4.编写SQL执行
uid=input("请输入用户id:")
uname=input("请输入用户姓名:")
uemail=input("请输入用户邮箱:")
# 语句参数化
parmas=[uid,uname,uemail]
sql="insert into bigdata2.user(uid,uname,uemail) values(%s,%s,%s)" #不管什么类型的数据,都是使用%s替换
db_cursor.execute(sql,parmas)
# 5.提交事务
db_conn.commit()
print("操作执行成功")
# 6.关闭游标
db_cursor.close()
# 关闭连接
db_conn.close()
案例:利用pymysql与md5实现注册与登录功能
# # 1.导入模块
import pymysql
import hashlib
# 2.创建连接对象
db_conn = pymysql.connect(host="localhost",
port=3306,
user="root",
password="123456",
database="db_users",
charset="utf8")
# 3.创建游标对象
db_cursor=db_conn.cursor()
print("------------注册------------")
# 4.编写SQL执行
username=input("请输入用户名:")
password=hashlib.md5(input("请输入密码:").encode("utf8")).hexdigest()
parmas=[username,password]
sql="insert into db_users.tb_user(username,password) values(%s,%s)" #不管什么类型的数据,都是使用%s替换
db_cursor.execute(sql,parmas)
# 5.提交事务
db_conn.commit()
print("注册成功")
print("------------登录------------")
# 定义初始状态 flag=1未登录,flag=0已登录
flag=1
while flag==1:
# 编写登录功能SQL执行
inusername=input("请输入用户名:")
# 对输入的密码进行加密
inpassword=hashlib.md5(input("请输入密码:").encode("utf8")).hexdigest()
sql="select username,password from db_users.tb_user"
db_cursor.execute(sql)
result=db_cursor.fetchall()
# 判断账号密码是否正确
for username,password in result:
if inusername==username:
if inpassword==password:
print("登陆成功~")
flag=0
break
else:
print("密码错误,登录失败,请继续登录")
break
else:
print("账号不存在,登录失败")
login = input("是否继续登录(y/n?)")
# 如输入n,退出登录循环
if login=="n":
flag=0
# 6.关闭游标
db_cursor.close()
# 关闭连接
db_conn.close()