python3基础2026.7.22
闭包的构成条件三步走第一步有嵌套存在外部函数函数内部定义了内部函数函数嵌套第二步有引用内部函数引用了外部函数作用域中的变量非全局变量第三步有返回return外部函数将内部函数作为返回值进行return案例一普通的嵌套函数def outer(): a 10 def inner(): pass # 内部函数没有使用a return inner f outer()内存实例图文本内存解释【调用 outer() 阶段】 栈空间(outer栈帧)├─ 变量 a → 内存地址0x0001 值10└─ 创建函数对象 inner → 堆地址0x1001堆内存0x1001 : inner函数对象⚠️ inner.closure None 【没有 cell 单元格】【outer执行完毕return inner】outer栈帧销毁└─ 局部变量a(0x0001) 引用计数变为0└─ GC回收地址0x0001a彻底消失变量 f → 指向堆 0x1001inner函数最终状态 f(0x1001) 保留但是变量a已经被销毁无法访问a2.【构成闭包】的代码关键内部函数引用外部变量def outer(): a 10 # 外部函数局部变量 def inner(): print(a) # ✅ 内部函数引用外部变量a return inner # f 接收内部函数对象 f outer()内存示例图文本内存讲解执行outer()操作系统开辟栈空间创建局部变量a10假设内存地址0x1001在内存中创建内部函数对象inner地址0x2001。检测到inner 引用了外部变量 aPython 自动给inner函数对象创建一个属性__closure__闭包单元格 cellcell单元格专门保存外部变量的内存地址0x1001。⭐重点inner 不再是单纯的函数它携带了单元格记录外部变量地址outer 函数执行完毕正常要销毁局部变量正常情况outer 栈销毁 →0x1001内存释放。但是cell 单元格持有0x1001的引用计数引用计数 ≠ 0 → GC 垃圾回收不能回收这块内存return inner变量f inner0x2001变量 f 指向内部函数对象只要 f 不被删除inner和它里面的cell就一直存在。执行f()inner 运行时通过 cell 单元格里保存的地址0x1001找到变量 a 的值打印。在闭包的内部实现对外部变量的修改操作nonlocal关键字nonlocal关键字用于在嵌套函数中声明一个变量不是局部变量而是来自外层函数的变量。使用nonlocal可以修改外层函数中的变量值而不仅仅是读取它。# 1.有嵌套 def outer(): # 局部变量 num 20 def inner(): # 2.有引用内部函数引用了外部函数的局部变量 nonlocal num num 10 print(fouter函数中的num变量值{num}) inner() print(f执行inner函数中的num变量值{num}) # # 3.有返回值把内部函数的名称返回》内存地址返回 # return inner # 调用outer函数 outer()输出结果使用场景当需要在嵌套函数中修改外层函数的变量时必须使用nonlocal声明。如果不使用nonlocalPython会认为这是一个新的局部变量。def counter(): count 0 def increment(): nonlocal count count 1 return count return increment与global的区别nonlocal用于访问外层函数的变量而global用于访问全局变量。两者都允许修改对应作用域的变量。global_var 10 def outer(): local_var 20 def inner(): global global_var nonlocal local_var global_var 1 local_var 1 inner() print(global_var, local_var)多层嵌套nonlocal可以在多层嵌套函数中使用它会沿着作用域链向上查找最近的变量。def outer(): x 1 def middle(): x 2 def inner(): nonlocal x x 3 inner() print(x) # 输出3 middle() print(x) # 输出1注意事项nonlocal声明的变量必须在外层函数中存在否则会引发SyntaxError。它不能用于全局变量也不能创建新的变量。def outer(): def inner(): nonlocal x # 错误x未在外层作用域定义 x 10 inner()闭包的综合案例案例一def func(): result 0 def inner(num): nonlocal result result num print(result) return inner func func() func(1) # 1 func(2) # 3运行结果代码分析先约定地址标识方便理解堆地址0x8001整数对象0堆地址0x9001inner函数对象堆地址0xA001cell 单元格保存对 result 对应整数对象的引用阶段 1执行func func()外层 func 调用1. 栈内存创建外层 func 栈帧栈帧内局部名字result→ 指针指向堆0x8001int 对象 02. 堆内存创建inner函数对象0x9001因为inner内部引用了外层变量resultPython 自动生成 cell 单元格0xA0013.return inner外层 func 函数执行结束外层 func 栈帧销毁栈上名字result消失关键cell(0xA001)仍然持有0x8001整数对象的引用 对象引用计数≠0GC不能回收堆上 0x8001全局名字func重新绑定指向堆地址0x9001inner 函数⚠重点现在不存在外层 func 了全局 func 变量就是 inner 函数cell 单元格持续保存着数字对象的引用。阶段 2第一次调用func(1)→inner(1)开辟 inner 临时栈帧形参num1nonlocal result告知解释器不要在 inner 栈内创建局部 result去 cell 寻找外层绑定对象result num等价逻辑通过 cell 单元格0xA001拿到指针 →0x8001对象0计算0 1 1新建整数对象 1地址0x8002✅修改 cell 单元格内部保存的指针cell (0xA001) 不再指向0x8001更新指针 →堆地址 0x8002int 对象 1原来的整数0(0x8001)失去所有引用后续会被 GC 回收print 输出1inner 临时栈帧销毁形参 num 消失当前内存状态全局func → inner(0x9001) inner绑定cell(0xA001) cell指针 → 0x8002int对象1阶段 3第二次调用func(2)→inner(2)新建 inner 临时栈帧num2通过 cell 单元格0xA001读取指向对象0x8002值1计算1 2 3新建对象3地址0x8003再次更新 cell 内指针cell(0xA001) →0x8003int对象3print 输出3inner 临时栈销毁通过闭包深入理解装饰器1.装饰器的定义就是给已有函数增加额外功能的函数它本质上就是一个闭包函数装饰器的功能特点不修改已有函数的功能特点不修改已有函数的调用方式给已有函数增加额外的功能2.装饰器的雏形代码示例#定义一个装饰器 #参数fn,要求传递要修饰函数的名称 #1.有嵌套 def check(fn):#fn为局部变量 fn 局部变量地址指向 comment def inner(): #编写装饰器功能 print(先登陆) #2.有引用 fn() #相当于 调用comment()方法 return inner#返回地址 #定义一个已有函数 def comment(): print(编写评论) # 调用装饰器代码装饰comment comment check(comment) #将comment的类名的内存地址传入check方法中 comment() #由于comment指向inner函数使用comment代表执行inner函数输出结果代码分析约定内存地址方便理解原始comment函数对象0x1001check内部生成的inner函数对象0x2001cell 单元格0x3001阶段 1执行comment check(comment)执行check(comment)全局名字comment指向0x1001传入 check形参fncheck 栈帧内局部变量名→ 指针指向0x1001在 check 内部创建inner函数对象0x2001inner 内部引用了外部变量fn形成闭包inner(0x2001) └─ __closure__ → cell单元格(0x3001) cell保存指针 → 0x1001原始comment函数3.return innercheck 函数执行结束check 栈帧销毁栈上局部名字fn消失但是cell(0x3001)依旧持有0x1001的引用原始 comment 函数不会被回收4.comment inner全局变量comment重新绑定✅ 旧关联comment → 0x1001断开✅ 新关联comment → 0x2001inner 函数阶段2执行comment等价调用innerdef inner(): print(先登陆) fn()打印先登陆执行fn()inner 通过自身 cell 单元格0x3001拿到指针0x1001调用原始函数对象0x1001输出编写评论内存链路简图执行完成 comment check(comment) 之后 全局变量 comment ──── inner(0x2001) ↓ cell单元格(0x3001) ↓ 原始comment函数(0x1001)核心结论装饰器本质Python 装饰器 闭包的典型应用check是装饰器外层函数inner闭包负责增强功能 调用原函数comment check(comment)是变量重绑定偷换了全局名字指向cell 单元格永久保存原始函数的地址保证在 inner 内部可以随时调用原函数装饰器的定义装饰器是一种设计模式允许在不修改原有代码结构的情况下动态地为函数或类添加额外功能。它通过将目标函数或类作为参数传递给另一个函数装饰器函数并在装饰器内部对目标函数进行包装或扩展最终返回增强后的函数。装饰器的语法装饰器通过符号加装饰器函数名放置在目标函数定义之前#1.有嵌套 def check(func): def inner(): #编写装饰器功能修饰代码 print(登陆功能) #2.与引用 func() #3.有返回 return inner #定义一个已有函数 check #用 修饰器名称 的注解 来调用定义的装饰器 def comment(): print(编写评论) #调用comment函数 comment()类装饰器装饰器也可以实现为类只需实现__call__方法class CountCalls: def __init__(self, func): self.func func self.num_calls 0 def __call__(self, *args, **kwargs): self.num_calls 1 print(fCall {self.num_calls} of {self.func.__name__}) return self.func(*args, **kwargs) CountCalls def say_hello(): print(Hello!) say_hello() # 输出Call 1 of say_hello \n Hello! say_hello() # 输出Call 2 of say_hello \n Hello!装饰器的作用装饰器的使用场景日志记录记录函数调用信息。性能测试统计函数执行时间。示例统计函数执行时间示例代码import time #定义一个装饰器用于获取某个函数的执行实际1.有嵌套 2.有引用 def get_time(fn): def inner(): #给fn函数添加额外的功能 start time.time() #执行了原函数 fn() end time.time() print(f{fn}函数执行一个花费了{end-start}s) #把内存函数的地址使用return返回 return inner #原有函数 get_time def func(): list1 [] for i in range(100000): list1.append(i) #调用函数 func()输出结果代码分析定义外层函数get_time、业务函数func语法糖get_time等价执行func get_time(func)。调用get_time(func)原func函数地址传入形参fn内部创建innerinner引用fn构成闭包随后返回inner。全局变量func重新绑定为inner函数对象。执行func()实际运行inner获取起始时间start通过闭包 cell 保存的地址调用原始func循环生成列表获取结束时间end计算并打印函数执行耗时。核心要点get_time执行完毕栈帧销毁但inner内 cell 单元格持有原func函数引用原函数不会被 GC 回收供后续调用。通用装饰器的使用1.装饰器带有参数的函数示例可以日志打印生成一个装饰器#编写装饰器,用于给每个函数增加一个日志输出功能 def logging(fn): def inner(num1,num2): print(f-- 输出日志正在{fn.__name__}执行函数--) fn(num1,num2) return inner logging def sum_num(num1,num2): result num1num2 print(result) sum_num(10,20)输出结果案例不定长参数 def logging(fn): def wrapper(*args,**kwargs): #添加装饰器代码输出日志信息 print(f-- 输出日志正在{fn.__name__}执行函数--) fn(*args,**kwargs) return wrapper logging def sum_num(*args,**kwargs): result 0 # *args代表不定长元组参数args (10,20) for num in args: result num #**kwargs代表不定长字典参数 kwargs {a:2,b:3) for num in kwargs.values(): result num print(result) #sum_mun带四个参数而且参数类型不用10和20以元组形式传递a 2 ,b 3以字典传递 sum_num(10,20,a 2,b 3) 输出结果带有返回装饰器返回装饰器是一种特殊类型的装饰器其核心功能是修改或增强被装饰函数的返回值。这类装饰器通常在被装饰函数执行完毕后对其返回结果进行加工、验证或转换再返回新的结果。基本结构def return_decorator(func): def wrapper(*args, **kwargs): # 调用原始函数并获取返回值 result func(*args, **kwargs) # 对返回值进行处理 modified_result ... # 处理逻辑 return modified_result return wrapper典型应用场景结果格式化将原始返回值转换为特定格式如JSON、字符串等def to_json(func): def wrapper(*args, **kwargs): import json result func(*args, **kwargs) return json.dumps(result) return wrapper to_json def get_data(): return {key: value}结果验证检查返回值是否符合预期条件def validate_non_negative(func): def wrapper(*args, **kwargs): result func(*args, **kwargs) if result 0: raise ValueError(Result must be non-negative) return result return wrapper结果缓存缓存函数返回值以避免重复计算def cache_result(func): cached {} def wrapper(*args): if args in cached: return cached[args] result func(*args) cached[args] result return result return wrapper类型转换强制将返回值转换为指定类型def enforce_type(target_type): def decorator(func): def wrapper(*args, **kwargs): result func(*args, **kwargs) return target_type(result) return wrapper return decorator enforce_type(float) def divide(a, b): return a / b注意事项链式调用多个返回装饰器会按从下到上的顺序生效。副作用处理确保装饰器不会意外修改原始返回值的不可变属性。性能影响复杂的返回值处理可能增加调用开销。高级用法结合参数化装饰器实现动态控制def multiply_return(factor): def decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) * factor return wrapper return decorator multiply_return(3) def get_number(): return 5返回装饰器通过拦截和修改返回值为函数提供灵活的后期处理能力是Python装饰器模式中的重要分支。python3网络编程socket计算机网络介绍1.IP地址的概念IP地址就是标识网络中设备的一个地址好比现实生活中的家庭地址。网络中的设备效果图2.IP地址的表现形式说明IP地址分为两类IPv4和IPv6IPv4是目前使用的IP地址IPv6是未来使用的IP地址IPv4是由点分十进制组成IPv6是由冒号十六进制组成3.IP地址的作用IP地址的作用是标识网络中唯一的一台设备的也就是说通过IP地址能找到网络中某台设备。IP地址作用效果图4.查看计算机的IP地址Linux和mac 使用ifconfig这个命令Windows使用ipconfig这个命令说明ifconfig与ipconfig都是查看网卡信息的网卡信息中包含这个设备对应的IP地址。5.检测网络是否正常检查网络是否正常使用ping命令检查网络是否正常效果图6.问题思考问不同电脑上的飞秋之间进行数据通信它是如何保证把数据给飞秋而不是其他软件答其实每运行一个网络程序都会有一个端口想要给对应程序发送数据找到对应的端口号即可。端口就是传输数据的通道好比教室的门就是数据传输必经之路。端口效果图而且每一个端口号都会有一个对应的端口号操作系统为了统一管理这么多端口就对端口进行了编号这就是端口号端口号其实就是一个数字好比我们现实生活中的门牌号想要找到端口通过端口号即可。最终通信结果通过ip找到对应的设备通过端口号找到对应的端口号然后通过端口号把数据给应用程序。7.扩展端口号扩展①知名端口号知名端口号是指众所周知的端口号范围从 0 到 1023这些端口号一般固定分配给一些服务比如 21 端口分配给 FTP文件传输协议服务22 端口分配给 SSH安全外壳协议主要用于远程连接与文件传输25 端口分配给 SMTP简单邮件传输协议服务80 端口分配给 HTTP 服务443 端口分配给 HTTPS 服务等等。②动态端口号一般程序员开发应用程序使用端口号称为动态端口号。 动态端口号的范围是从 1024 到 65535如果程序员开发的程序没有设置端口号操作系统会在动态端口号这个范围内随机生成一个给开发的应用程序使用。注意当运行一个程序默认会有一个端口号当程序退出时所占用的这个端口号就会被释放。TCP的介绍1、网络应用程序之间的通信流程之前我们学习了 IP 地址和端口号通过 IP 地址能够找到对应的设备然后再通过端口号找到对应的端口再通过端口把数据传输给应用程序这里要注意数据不能随便发送在发送之前还需要选择一个对应的传输协议保证程序之间按照指定的传输规则进行数据的通信而这个传输协议就是我们今天学习的 TCP。2.TCP概念TCP传输控制协议它是一种面向连接的、可靠的、基于字节流的传输层通信协议。面向连接的效果图3.TCP通信步骤1.创建连接2.传输数据3.关闭连接4.TCP协议的优点可靠性高TCP通过确认机制、重传机制和校验和确保数据准确无误地传输。每发送一个数据段都会等待接收方的确认未收到确认时会重传保证数据完整性。有序传输TCP为每个数据包分配序列号接收方按序列号重组数据确保数据按发送顺序到达避免乱序问题。流量控制通过滑动窗口机制动态调整发送速率防止接收方因缓冲区不足导致数据丢失有效管理网络拥塞。连接导向通信前需建立三次握手连接结束后通过四次挥手释放连接。这种面向连接的特性适合需要稳定传输的场景如文件传输、网页浏览。支持全双工通信允许双方同时发送和接收数据提高通信效率。5.TCP协议的缺点建立连接开销大三次握手和四次挥手过程引入额外延迟尤其在短连接场景如HTTP请求中显著影响性能。传输效率较低为保证可靠性TCP需维护序列号、确认、重传等机制增加协议头开销通常20字节占用更多带宽和CPU资源。实时性差重传机制和拥塞控制可能导致延迟波动不适合实时性要求高的应用如视频会议、在线游戏。灵活性不足TCP严格保证数据顺序和完整性某些场景如音视频流允许部分数据丢失但需要低延迟此时TCP的机制反而成为瓶颈。拥塞控制可能过保守TCP的拥塞避免算法如慢启动在网络状况良好时可能无法充分利用带宽降低吞吐量。适用场景对比适用场景需高可靠性的应用网页浏览、电子邮件、文件传输。不适用场景实时音视频、在线游戏、IoT传感器数据等低延迟或可容忍丢包的应用通常选用UDP。socket的介绍套接字1.问题思考到目前为止我们学习了 IP 地址和端口号还有 TCP 传输协议为了保证数据的完整性和可靠性我们使用 TCP 传输协议进行数据的传输为了能够找到对应设备我们需要使用 IP 地址为了区别某个端口的应用程序接收数据我们需要使用端口号那么通信数据是如何完成传输的呢2.socket套接字socket是进程之间通信一个工具好比现实生活中的插座所有的家用电器想要工作都是基于插座进行进程之间想要进行网络通信需要基于这个socket。3.socket的作用与应用场景socket的作用负责进程之间的网络数据传输好比数据的搬运工socket使用场景不夸张的说只有跟网络相关的应用程序或者软件都使用到了socketTCP网络应用程序开发流程1.介绍TPC网络应用程序开发分为TCP客户端程序开发TCP服务端程序开发说明客户端程序是指运行在用户设备上的程序服务端程序是指运行在服务器设备上的程序专门为客户提供数据服务2.具体流程介绍TCP客户端开发五步走socket类的介绍1.导入socket模块 import socket 2.创建客户端socket对象使用socket类 socket.socket(AddressFamily,Type)客户端socket类的参数和方法说明参数名说明AddressFamilyIP 地址类型分为 IPv4 和 IPv6图中笔误写为 TPv4Type传输协议类型TCP/UDP开发客户端需要使用的函数方法名说明connect与服务端套接字建立网络连接send向服务端发送数据recv接收服务端返回的数据close关闭当前套接字连接释放端口资源python3编码转换1.为什么要学习编码转换在计算机网络中时间都是以二进制的形式进行传输的。所以在网络传输数据的时候数据需要先编码转化为二进制bytes)数据类型2.数据的编码转换转换方法说明函数名说明encode编码将字符串转化为字节码decode解码将字节码转化为字符串提示encode和decode函数可以接受参数encoding是指在编码解码过程中使用的编码方案。字符串编码str.encode(encodingutf-8)二进制解码bytes.decode(encoding utf-8)客户端代码示例import socket #1.创建套接字对象(socket.AF_INET IPv4,socket.SOCK_STREAM TCP协议) tcp_client_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) #2.与服务器端建立连接 tcp_client_socket.connect((127.0.0.1, 8080)) #3.发送消息不能是文本类型必须是字节流数据 tcp_client_socket.send(hello world.encode(utf-8)) #4.接受消息服务器端返回的数据默认类型都是字节流类型必须进行解码 recv_data tcp_client_socket.recv(1024).decode(utf-8) print(recv_data) #5.关闭套接字对象 tcp_client_socket.close()TCP服务器端程序开发1.开发TCP服务端程序开发步骤① 创建服务端端套接字对象② 绑定端口号③ 设置监听④ 等待接受客户端的连接请求⑤ 接收数据⑥ 发送数据⑦ 关闭套接字2.示例代码import socket # 1. 创建TCP服务端套接字 tcp_server_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2. 绑定本机IP和端口要和客户端connect里的端口8080保持一致 tcp_server_socket.bind((127.0.0.1, 8080)) # 3. 设置监听参数代表最大等待连接数 tcp_server_socket.listen(128) print(服务端已启动等待客户端连接...) # 4. 等待接收客户端连接accept阻塞等待 client_conn, client_addr tcp_server_socket.accept() print(f客户端 {client_addr} 已接入) # 5. 接收客户端发来的字节数据解码成字符串 recv_data client_conn.recv(1024).decode(utf-8) print(收到客户端消息, recv_data) # 6. 给客户端回发响应字符串转字节发送 client_conn.send(消息已收到.encode(utf-8)) # 7. 关闭和当前客户端的连接 client_conn.close() # 8. 关闭服务端主套接字不再接收新连接 tcp_server_socket.close()3.服务器端开发多客户版本#导入模块 import socket #1.创建套接字对象 tcp_server_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) #2.绑定ip和端口,其参数是一个元组类型的数据 tcp_server_socket.bind((127.0.0.1, 8080)) #3.设置监听 tcp_server_socket.listen(128) #4.等待客户端连接阻塞 while True: new_socket,ip_port tcp_server_socket.accept() #5.接收客户端发送过来的消息 recv_data new_socket.recv(1024).decode(utf-8) print(f{ip_port}客户端发送的消息{recv_data}) #6.处理请求把处理结果返回客户端 content 信息已经接受.encode(utf-8) new_socket.send(content) #7.关闭套接字 new_socket.close()创建服务端套接字对象socket.socket()绑定端口bind()设置监听listen(128)等待连接accept()阻塞接收数据recv().decode()发送响应send(编码后字节数据)关闭和当前客户端的连接new_socket.close()TCP服务器端开发面向对象单线程代码示例#导入模块 import socket #创建一个webserver服务器端类 class WebServer(object): #用于对象初始化 def __init__(self): #创建套接字对象 tcp_server_socket socket.socket(socket.AF_INET,socket.SOCK_STREAM) #绑定ip和端口号 tcp_server_socket.bind((,8080)) #设置监听 tcp_server_socket.listen(128) #把tcp_server_socket赋值给自身 self.tcp_server_socket tcp_server_socket #定义一个handle_client_request def handle_client_request(self,new_socket,ip_port): #接收客户端请求 recv_data new_socket.recv(1024).decode(utf-8) print(f{ip_port}客户端发送的消息{recv_data}) #返回消息给客户端 content 已收到.encode(utf-8) new_socket.send(content) #处理完成后关闭新套接字对象 new_socket.close() #定义一个start方法用于启动WebServer,接受客户端 def start(self): while True: #等待客户端连接 new_socket,ip_port self.tcp_server_socket.accept() #定义一个方法用于接收和发送消息 self.handle_client_request(new_socket,ip_port) #def __str__(self): 输出对象的信息必须返回字符串 # def __del__(self): 当销毁对象时会自动调用__del__魔术方法 #创建程序执行入口实例化WebServer类生成对象 if __name__ __main__: #实例化对象 ws WebServer() #调用自身方法用于启动服务 ws.start()代码讲解1. 类定义 class WebServer (object)采用面向对象编程思想封装 TCP 服务端将套接字创建、端口绑定、监听、客户端请求处理全部封装在类内部结构清晰便于功能扩展。2.init构造方法程序实例化对象时自动执行。socket.socket (socket.AF_INET,socket.SOCK_STREAM)创建 IPv4、TCP 协议的服务端套接字bind ((,8080))绑定端口 8080。填写空字符串 代表监听本机所有网卡 IP局域网内其他设备均可访问如果填写 127.0.0.1则仅本机程序能够连接listen (128)开启监听参数 128 代表等待连接队列最大数量将套接字对象赋值给实例属性 self.tcp_server_socket供类中其他方法调用。3. handle_client_request(new_socket,ip_port)负责处理单个客户端的通信请求。new_socket专属套接字专门用于和当前接入的客户端收发数据ip_port元组类型保存客户端的 IP 地址与端口recv (1024)接收客户端数据一次最多读取 1024 字节通过 decode (utf-8) 将字节码转为字符串原有代码只实现打印客户端消息缺少数据响应与套接字关闭逻辑。4. start () 启动方法while True 无限循环实现持续接收客户端连接accept () 是阻塞方法若无客户端发起连接程序会暂停在此处等待成功建立连接后调用 handle_client_request 处理本次客户端通信注意当前为单线程串行模式同一时间只能处理一个客户端后续客户端需要排队等待。TCP服务器端开发面向对象多线程--直接取消socket.close()#导入模块 import socket #创建一个webserver服务器端类 class WebServer(object): #用于对象初始化 def __init__(self): #创建套接字对象 tcp_server_socket socket.socket(socket.AF_INET,socket.SOCK_STREAM) #绑定ip和端口号 tcp_server_socket.bind((,8080)) #设置监听 tcp_server_socket.listen(128) #把tcp_server_socket赋值给自身 self.tcp_server_socket tcp_server_socket #定义一个handle_client_request def handle_client_request(self,new_socket,ip_port): #接收客户端请求 recv_data new_socket.recv(1024).decode(utf-8) print(f{ip_port}客户端发送的消息{recv_data}) #返回消息给客户端 content 已收到.encode(utf-8) new_socket.send(content) #处理完成后关闭新套接字对象 #new_socket.close() #定义一个start方法用于启动WebServer,接受客户端 def start(self): while True: #等待客户端连接 new_socket,ip_port self.tcp_server_socket.accept() #定义一个方法用于接收和发送消息 self.handle_client_request(new_socket,ip_port) #def __str__(self): 输出对象的信息必须返回字符串 # def __del__(self): 当销毁对象时会自动调用__del__魔术方法 #创建程序执行入口实例化WebServer类生成对象 if __name__ __main__: #实例化对象 ws WebServer() #调用自身方法用于启动服务 ws.start()