Python基础(4)-多任务编程、正则表达式

第八章 多任务

多任务的最大好处是充分利用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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值