python基础day06
1.内置模块OS:
- 简介:Python内置的与操作系统文件相关的模块,该模块中语句的执行结果通常与操作系统有关,即有些函数的运行效果在Windows操作系统和MacOS系统中不一样。
- 常用函数:
函数名称 | 描述说明 |
getcwd() | 获取当前的工作路径 |
listdir(path) | 获取path路径下的文件和目录信息,如果没有指定path则获取当前路径下的文件和目录信息 |
mkdir(path) | 在指定路径下创建目录(文件夹),如果要创建的文件夹存在,程序会报错FileExitsError |
makedirs(path) | 创建多级目录 |
rmdir(path) | 删除path下的空目录,如果要删除的目录不存在,程序报错FileNotFoundError |
removedirs(path) | 删除多级目录 |
chdir(path) | 把path设置为当前目录 |
walk(path) | 遍历目录树,结果为元组,包含所有路径名、所有目录列表和文件列表 |
remove(path) | 删除path指定的文件,如果要删除的目录不存在,程序报错FileNotFoundError |
rename(old,new) | 将old重命名为new |
stat(path) | 获取path指定的文件信息 |
startfile(path) | 启动path指定的文件 |
- os.path模块:
简介:是os模块的子模块,也提供了一些目录或文件的操作函数。
常用函数:
函数名称 | 描述说明 |
abspath(path) | 获取目录或文件的绝对路径 |
exists(path) | 判断目录或文件在磁盘上是否存在,结果为bool类型,如果目录或文件在磁盘上存在,结果为True,否则为False |
join(path,name) | 将目录与目录名或文件名进行拼接,相当于字符串的“+”操作 |
splitext() | 分别获取文件名和后缀名,结果是元组类型(文件名,后缀名) |
basename(path) | 从path中提取文件名 |
dirname(path) | 从path中提取路径(不包含文件名) |
isdir(path) | 判断path是否是有效路径 |
isfile(path) | 判断file是否是有效文件 |
2.网络编程与通信协议:
- 通信协议:接入网络所要遵守的“规则”,目前全球通用的通信协议即Internet协议。
- 七层协议与四层协议:
- IP协议:IP协议是整个TCP/IP协议族的核心, IP地址就是互联网上计算机的唯一标识。目前的IP地址有两种表示方式,即IPv4和IPv6。在命令行下使用ipconfig命令可以查看本机的IP地址。
- TCP协议:TCP(Transmission Control Protocol)协议即传输控制协议,是建立在IP协议基础之上的。TCP协议负责两台计算机之间建立可靠连接,保证数据包按顺序发送到。它是一种可靠的、一对一的、面向有连接的通信协议。
- TCP/IP协议中的四个层次:
- TCP/IP协议数据发送和数据接收:
- TCP协议的三次握手:
- UDP协议:UDP协议又被称为用户数据包协议(User DatagramProtocol),它是面向无连接的协议,只要知道对方的IP地址和端口,就可以直接发送数据包,由于是面向无连接的,所以无法保证数据一定会到达接收方。
- 端口号:区分计算机中的运行的应用程序的整数。端口号的取值范围是0到65535,一共65536个,其中80这个端口号分配给了HTTP服务,21这个端口号分配给了FTP服务。
- TCP协议与UDP协议的区别:
TCP协议 | UDP协议 | |
连接方面 | 面向连接的 | 面向无连接 |
连接方面 | 传输消息可靠、不丢失、按顺序到达 | 无法保证不丢包 |
传输效率方面 | 传输效率相对较低 | 传输效率高 |
连接对象数量方面 | 只能是点对点、一对一 | 支持一对一、一对多、多 对多的交互通信 |
3.Socket:
- Socket通信模拟图:
- Socket对象的常用方法:
方法名称 | 功能描述 |
bind((ip,port)) | 绑定IP地址和端口 |
listen(N) | 开始TCP监听,N表示操作系统挂起的最大连接数量,取值范围1-5之间,一般设置为5 |
accept() | 被动接收TCP客户端连接,阻塞式 |
connect((ip,port)) | 主动初始化TCP服务器连接 |
recv(size) | 接收TCP数据,返回值为字符串类型,size表示要接收的最大数据量 |
send(str) | 发送TCP数据,返回值是要发送的字节数量 |
sendall(str) | 完整发送TCP数据,将str中的数据发送到连接的套接字,返回之前尝试发送所有数据,如果成功为None,失败抛出异常 |
recvfrom() | 接收UDP数据,返回值为一个元组(data,address),data表示接收的数据,address表示发送数据的套接字地址 |
sendto(data,(ip,port)) | 发送UDP数据,返回值是发送的字节数 |
close() | 关闭套接字 |
4.TCP通信:
- TCP服务器端流程如下:
(1)使用socket类创建一个套接字对象。
(2)使用bind((ip,port))方法绑定IP地址和端口号。
(3)使用listen()方法开始TCP监听。
(4)使用accept()方法等待客户端的连接。
(5)使用recv()/send()方法接收/发送数据6.使用close()关闭套接字。
from socket import socket,AF_INET,SOCK_STREAM
# AF_INET 用于internet之间的进程通信
# SOCK_STREAM表示的是TCP协议编程# (1)创建socket对象
server_socket=socket(AF_INET,SOCK_STREAM)# (2)绑定IP地址和端口
ip='127.0.0.1'
port=8888
server_socket.bind((ip,port))# (3)使用listen()开始监听(5表示最大连接数量)
server_socket.listen(5)# (4)等待客户端的连接
client_socket,client_addr=server_socket.accept()# (5)接收来自客户端的数据
data=client_socket.recv(1024)
print("客户端发送过来的数据为:",data.decode("utf-8"))# (6)关闭socket
server_socket.close()
- TCP客户端的流程如下:
(1)使用socket类创建一个套接字对象。
(2)使用connect((host,port))设置连接的主机IP和主机设置的端口号。
(3)使用recv()/send()方法接收/发送数据。
(4)使用close()关闭套接字。
import socket
# (1)创建socket对象
client_socket = socket.socket()# (2)IP地址和主机端口,向服务端发送连接请求
ip='127.0.0.1'
port=8888
client_socket.connect((ip,port))# (3)发送数据
client_socket.send("Welcome to python world".encode('utf-8'))# (4)关闭
client_socket.close()
- 客户端与服务器端双向通信示意图:
- 服务端与客户端多次通信代码示例:
服务端代码:
import socket
# (1)创建socket对象
socket_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)# (2)绑定IP地址和端口号
socket_server.bind(("127.0.0.1",8888))# (3)设置最大连接数量
socket_server.listen(5)# (4)等待客户连接
client_sock,client_addr=socket_server.accept()# (5)接收来自客服端的数据
info=client_sock.recv(1024).decode("utf-8")
while info!="bye":if info!="":print("接收到的数据是:", info)data=input("请输入要发送的数据:") # 服务端要返回的数据client_sock.send(data.encode("utf-8")) # 向客户端响应数据if data=="bye":breakinfo=client_sock.recv(1024).decode("utf-8")# (6)关闭socket
socket_server.close()
client_sock.close()
客户端代码:
import socket
# (1)创建socket对象
client_socket = socket.socket()# (2)主机的IP和端口号
client_socket.connect(('127.0.0.1',8888))# (3)客户端先发送数据
info=""
while info!="bye":# 准备要发送的数据send_data=input("请输入客户端要发送的数据:")client_socket.send(send_data.encode("utf-8"))if send_data=="bye":breakinfo=client_socket.recv(1024).decode("utf-8")print("收到服务器响应的数据:",info)# (4)关闭socket对象
client_socket.close()
5.UDP通信:
- 客户端与服务端通信代码示例:
服务端代码:
from socket import socket,AF_INET,SOCK_DGRAM
# (1)创建socket对象
recv_socket=socket(AF_INET,SOCK_DGRAM)# (2)绑定IP地址和端口
recv_socket.bind(('127.0.0.1',8888))# (3)接收来自发送方的数据
recv_data,addr=recv_socket.recvfrom(1024)
print("接收到的数据为:",recv_data.decode("utf-8"))# (4)准备回复对方的数据
data=input("请输入要回复的数据:")# (5)回复
recv_socket.sendto(data.encode("utf-8"),addr)# (6)关闭
recv_socket.close()
客户端代码:
from socket import socket, AF_INET, SOCK_DGRAM
# (1)创建socket对象
send_socket=socket(AF_INET, SOCK_DGRAM)# (2)准备发送的数据
data=input("请输入要发送的数据:")# (3)指定接收方的IP地址和端口
ip_port=("127.0.0.1",8888)# (4)发送数据
send_socket.sendto(data.encode("utf-8"),ip_port)# 接收数据
recv_data,addr=send_socket.recvfrom(1024)
print("接收到的数据是:",recv_data.decode("utf-8"))# (5)关闭socket
send_socket.close()
6.程序与进程:
- 程序:英文单词为Program,是指一系列有序指令的集合,使用编程语言所编写,用于实现一定的功能。
- 进程:进程则是指启动后的程序,系统会为进程分配内存空间。
- 创建进程的方式:
方式一 : Process(group=None,target,name,args,kwargs)
参数说明:
(1) group:表示分组,实际上不使用,值默认为None即可。
(2)target:表示子进程要执行的任务,支持函数名。
(3)name:表示子进程的名称。
(4)args:表示调用函数的位置参数,以元组的形式进行传递。
(5)kwargs:表示调用函数的关键字参数,以字典的形式进行传递。
from multiprocessing import Process
import os,timedef test():print(f"我是子进程,我的PID是:{os.getpid()},我的父进程是:{os.getppid()}")time.sleep(1)lst=[]
if __name__ == '__main__':print("主进程开始执行")for i in range(5):p=Process(target=test)p.start()lst.append(p)for item in lst:item.join() # 阻塞主进程print("主进程执行结束")
方式二 : class 子进程(Process):
pass
from multiprocessing import Process
import os,time
class SubProcess(Process):def __init__(self,name):super().__init__()self.name=namedef run(self):print(f"子进程名称:{self.name},PID:{os.getpid()},父进程:{os.getppid()}")if __name__ == '__main__':print("父进程开始执行")lst=[]for i in range(6):p1=SubProcess(f"进程:{i}")p1.start()lst.append(p1)for item in lst:item.join()print("父进程执行结束")
- Process常见的方法和属性:
方法/属性名称 | 功能描述 |
name | 当前进程实例别名 ,默认为Process-N |
pid | 当前进程对象的PID值 |
is_alive() | 进程是否执行完,没执行完结果为True,否则为False |
join(timeout) | 等待结束或等待timeout秒 |
start() | 启动进程 |
run() | 如果没有指定target参数,则启动进程后,会调用父类中的 run方法 |
terminate() | 强制终止进程 |
7.Pool进程池:
- 进程池的原理是:创建一个进程池,并设置进程池中最大的进程数量。假设进程池中最大的进程数为3,现在有10个任务需要执行,那么进程池一次可以执行3个任务,4次即可完成全部任务的执行。
- 创建进程池的语法结构:进程池对象=PooI(N)
- 进程池常用的方法:
方法名 | 功能描述 |
apply _async(func,args,kwargs) | 使用非阻塞方式调用函数func |
apply(func,args,kwargs) | 使用阻塞方式调用函数func |
close() | 关闭进程池,不再接收新任务 |
terminate() | 不管任务是否完成,立即终止 |
join0 | 阻塞主进程,必须在terminate()或close()之后使用 |
- 非阻塞方式:
from multiprocessing import Pool
import os,time
def task(name):print(f"子进程PID:{os.getpid()},执行的任务:{name}")time.sleep(1)if __name__ == '__main__':start=time.time()print("主进程开始执行")p=Pool(3)for i in range(10):p.apply_async(func=task,args=(i,))p.close() # 关闭主进程不再接收新任务p.join() # 阻塞父进程,等待所有子任务执行完毕后,才会执行父进程中的代码print("所有子进程执行完毕,主进程执行结束")print(time.time()-start) # 5.294420003890991 每次执行三个任务,共执行4次
- 阻塞方式:
from multiprocessing import Pool
import os,time
def task(name):print(f"子进程PID:{os.getpid()},执行的任务:{name}")time.sleep(1)if __name__ == '__main__':start=time.time()print("主进程开始执行")p=Pool(3)for i in range(10):p.apply(func=task,args=(i,))p.close() # 关闭主进程不再接收新任务p.join() # 阻塞父进程,等待所有子任务执行完毕后,才会执行父进程中的代码print("所有子进程执行完毕,主进程执行结束")print(time.time()-start) # 11.40873122215271 每次执行一个任务,共执行10次
- 并发和并行:
并发:是指两个或多个事件同一时间间隔发生,多个任务被交替轮换着执行
并行:是指两个或多个事件在同一时刻发生,多个任务在同一时刻在多个处理器上同时执行
8.队列:
- 队列:进程之间可以通过队列(Queue)进行通信,队列是一种先进先出(FirstIn First Out)的数据结构。
- 创建队列的语法结构:队列对象=Queue(N)
- 队列常用方法:
方法名称 | 功能描述 |
qsize() | 获取当前队列包含的消息数量 |
empty() | 判断队列是否为空,为空结果为True,否则为False |
full() | 判断队列是否满了,满结果为True,否则为False |
get(block=True) | 获取队列中的一条消息,然后从队列中移除,block默认值为True |
get_nowait() | 相当于get(block=False),消息队列为空时,抛出异常 |
put(item,block=True) | 将item消息放入队列,block默认为True |
put_nowait(item) | 相当于put(item,block=False),消息队列为满时,抛出异常 |
- 代码示例:
from multiprocessing import Queue
if __name__ == '__main__':q=Queue(3) # 创建队列q.put("hello") # 将hello放入队列q.put("python") # 将python放入队列q.put("world") # 将world放入队列q.get() # 将hello从队列中移除if not q.empty():for i in range(q.qsize()):print(q.get()) # python world
- q.put(item,block=True,timeout=2)
put中的第三个参数单位是秒,表示等待n秒后,队列没有空位置就抛出异常
from multiprocessing import Queueif __name__ == '__main__':q = Queue(3)q.put("hello")q.put("world")q.put("python")q.put("java",block=True,timeout=2) # 等待2秒,队列没有空位置就抛出异常
9.线程:
- 线程:线程是CPU可调度的最小单位,被包含在进程中,是进程中实际的运作单位。一个进程中可以拥有N多个线程并发执行,而每个线程并行执行不同的任务。
- 创建线程:
方式一 : 函数式创建线程:t=Thread(group,target,name,args,kwargs)
参数说明:
(1)group:创建线程对象的进程组
(2)target:创建的线程对象所要执行的目标函数
(3)name:创建线程对象的名称,默认为“Thread-n”
(4)args:用无组以位置参数的形式传入target对应函数的参数
(5)kwargs:用字典以关键字参数的形式传入target对应函数的参数
方式二 : 使用Thread子类创建线程
(1)自定义类继承threading模块下的Thread类
(2)实现run方法
# 函数式创建线程
import threading
from threading import Thread
import time
def test():for i in range(3):time.sleep(1)print(f"线程:{threading.current_thread().name}正在执行{i}")
if __name__ == '__main__':start = time.time()print("主线程开始执行")lst=[Thread(target=test) for i in range(2)]for item in lst:item.start()for item in lst:item.join()print(f"一共耗时:{time.time()-start}秒")# 使用类创建线程
import threading
from threading import Thread
import time
class SubThread(Thread):def run(self):for i in range(3):time.sleep(1)print(f"线程:{threading.current_thread().name}正在执行{i}")
if __name__ == '__main__':start = time.time()print("主线程开始执行")lst=[SubThread() for i in range(2)]for item in lst:item.start()for item in lst:item.join()print("主线程执行完毕")
- 线程操作共享数据的安全性问题:
由于多个线程之间是并发执行,每个线程中的多个任务是并行执行的,就会导致不同线程中的任务会操作同一个全局变量,造成共享数据的安全性问题,因此需要使用Lock对共享数据进行锁定和解锁。
# 售票案例
from threading import Thread,Lock
import threading
import time
lock_obj = Lock()
ticket=50
def sale_ticket():global ticketfor i in range(100): # 每个排队窗口假设有100人lock_obj.acquire() # 上锁if ticket > 0:print(f"{threading.current_thread().name}正在出售第{ticket}张票")ticket -= 1time.sleep(1)lock_obj.release() # 释放锁if __name__ == '__main__':for i in range(3): # 创建三个线程,代表三个窗口t = Thread(target=sale_ticket)t.start()
10.生产者与消费者模式
生产者与消费者模式:是线程模型中的经典问题,与编程语言无关。当程序中出现了明确的两类任务,一个任务负责生产数据,一个任务负责处理生产的数据时就可以使用该模式。
- Python内置模块queue由的Queue类:
方法名称 | 功能描述 |
put(item) | 向队列中放置数据,如果队列为满,则阻塞 |
get() | 从队列中取走数据,如果队列为空,则阻塞 |
join() | 如果队列不为空,则等待队列变为空 |
task_done() | 消费者从队列中取走一项数据,当队列变为空时,唤醒调用join()的线程 |