Python-Python高阶技巧:闭包、装饰器、设计模式、多线程、网络编程、正则表达式、递归

版本说明

当前版本号[20231018]。

版本修改说明
20231018初版

目录

文章目录

  • 版本说明
  • 目录
  • Python高阶技巧
    • 闭包
      • 简单闭包
      • 修改外部函数变量的值
      • 实现以下atm取钱的闭包实现了
      • 闭包注意事项
    • 装饰器
      • 装饰器的一般写法(闭包写法)
      • 装饰器的语法糖写法
    • 设计模式
      • 单例模式
        • 单例的实现模式
      • 工厂模式
    • 多线程
      • 进程、线程和并行执行
        • 进程、线程
        • 并行执行
      • 多线程编程
        • threading模块
      • 多线程练习案例
    • 网络编程
      • 服务端开发
        • Socket
        • 客户端和服务端
        • Socket服务端编程
        • 实现服务端并结合客户端进行测试
      • 客户端开发
        • Socket客户端编程
        • 服务端客户端相互通讯
    • 正则表达式
      • 基础匹配
        • 正则的三个基础方法
      • 元字符匹配
        • 单字符匹配
        • 数量匹配
        • 边界匹配
        • 分组匹配
    • 递归
      • 递归找文件

Python高阶技巧

闭包

image-20230731205024239

image-20230731205031917

通过全局变量account_amount来记录余额

尽管功能实现是ok的,但是仍有问题:

  • 代码在命名空间上(变量定义)不够干净、整洁
  • 全局变量有被修改的风险

如何解决?

  • 将变量定义在函数内部是行不通的
  • 我们需要使用闭包

在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包

image-20230731205215934

简单闭包

image-20230731205250838

修改外部函数变量的值

image-20230731205744964

实现以下atm取钱的闭包实现了

image-20230731205822732

闭包注意事项

优点,使用闭包可以让我们得到:

无需定义全局变量即可实现通过函数,持续的访问、修改某个值

•闭包使用的变量的所用于在函数内,难以被错误的调用修改

缺点:

•由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存

示例代码:

def account_create(initial_amount=0):def atm(num, deposit=True):nonlocal initial_amountif deposit:initial_amount += numprint(f"存款:+{num}, 账户余额:{initial_amount}")else:initial_amount -= numprint(f"存款:-{num}, 账户余额:{initial_amount}")return atmatm = account_create()
atm(300)
atm(200)
atm(100, False)

装饰器

装饰器其实也是一种闭包, 其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能

image-20230731210813945

希望给sleep函数,增加一个功能:

•在调用sleep前输出:我要睡觉了

•在调用sleep后输出:我起床了

装饰器的一般写法(闭包写法)

image-20230731210912523

装饰器的语法糖写法

image-20230731210949632

示例代码:

def outer(func):def inner():print("我要睡觉了")func()print("我起床了")return inner@outer
def sleep():import randomimport timeprint("睡眠中……")time.sleep(random.randint(1, 5))sleep()

设计模式

设计模式是一种编程套路,可以极大的方便程序的开发。

最常见、最经典的设计模式,就是我们所学习的面向对象了。

除了面向对象外,在编程中也有很多既定的套路可以方便开发,我们称之为设计模式:

  • 单例、工厂模式
  • 建造者、责任链、状态、备忘录、解释器、访问者、观察者、中介、模板、代理模式
  • 等等模式

单例模式

image-20230731211135653

创建类的实例后,就可以得到一个完整的、独立的类对象。

通过print语句可以看出,它们的内存地址是不相同的,即t1和t2是完全独立的两个对象。

image-20230731211149898

某些场景下, 我们需要一个类无论获取多少次类对象,都仅仅提供一个具体的实例

用以节省创建类对象的开销和内存开销,比如某些工具类,仅需要1个实例,即可在各处使用

这就是单例模式所要实现的效果。

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。

在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

  • 定义: 保证一个类只有一个实例,并提供一个访问它的全局访问点
  • 适用场景:当一个类只能有一个实例,而客户可以从一个众所周知的访问点访问它时。
单例的实现模式

image-20230731211352989

工厂模式

当需要大量创建一个类的实例的时候, 可以使用工厂模式。

即,从原生的使用类的构造去创建对象的形式迁移到,基于工厂提供的方法去创建对象的形式。

image-20230731211609598

  • 使用工厂类的get_person()方法去创建具体的类对象

优点:

  • 大批量创建对象的时候有统一的入口,易于代码维护
  • 当发生修改,仅修改工厂类的创建方法即可
  • 符合现实世界的模式,即由工厂来制作产品(对象)

示例代码:

class Person:passclass Worker(Person):passclass Student(Person):passclass Teacher(Person):passclass PersonFactory:def get_person(self, p_type):if p_type == 'w':return Worker()elif p_type == 's':return Student()else:return Teacher()pf = PersonFactory()
worker = pf.get_person('w')
stu = pf.get_person('s')
teacher = pf.get_person('t')

多线程

进程、线程和并行执行

进程、线程

现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支持“多任务”的操作系统。

进程: 就是一个程序,运行在系统之上,那么便称之这个程序为一个运行进程,并分配进程ID方便系统管理。

线程:线程是归属于进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位。

进程就好比一家公司,是操作系统对程序进行运行管理的单位

线程就好比公司的员工,进程可以有多个线程(员工),是进程实际的工作者

操作系统中可以运行多个进程,即多任务运行

一个进程内可以运行多个线程,即多线程运行

注意点:

进程之间是内存隔离的, 即不同的进程拥有各自的内存空间。 这就类似于不同的公司拥有不同的办公场所。

线程之间是内存共享的,线程是属于进程的,一个进程内的多个线程之间是共享这个进程所拥有的内存空间的。

这就好比,公司员工之间是共享公司的办公场所。

image-20230731212151538

并行执行

并行执行的意思指的是同一时间做不同的工作

进程之间就是并行执行的,操作系统可以同时运行好多程序,这些程序都是在并行执行。

除了进程外,线程其实也是可以并行执行的。

也就是比如一个Python程序,其实是完全可以做到:

  • 一个线程在输出:你好
  • 一个线程在输出:Hello

像这样一个程序在同一时间做两件乃至多件不同的事情, 我们就称之为:多线程并行执行

多线程编程

threading模块

绝大多数编程语言,都允许多线程编程,Pyhton也不例外。

Python的多线程可以通过threading模块来实现。

image-20230731212446548

image-20230731212526327

image-20230731212551780

多线程练习案例

import time
import threadingdef sing(msg):while True:print(msg)time.sleep(1)def dance(msg):while True:print(msg)time.sleep(1)if __name__ == '__main__':#创建一个唱歌的线程sing_thread = threading.Thread(target=sing, args=("我要唱歌!",))#创建一个跳舞的线程dance_thread = threading.Thread(target=dance, kwargs={"msg": "我在跳舞!"})#使线程开始工作
sing_thread.start()
dance_thread.start()

网络编程

服务端开发

Socket

socket (简称 套接字) 是进程之间通信一个工具,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,进程之间想要进行网络通信需要socket。

Socket负责进程之间的网络数据传输,好比数据的搬运工。

image-20230731212757604

客户端和服务端

2个进程之间通过Socket进行相互通讯,就必须有服务端和客户端

Socket服务端:等待其它进程的连接、可接受发来的消息、可以回复消息

Socket客户端:主动连接服务端、可以发送消息、可以接收回复

image-20230731212905181

Socket服务端编程

主要分为如下几个步骤:

  1. 创建socket对象

image-20230731213004113

  1. 绑定socket_server到指定IP和地址

image-20230731213010971

  1. 服务端开始监听端口

image-20230731213017624

  1. 接收客户端连接,获得连接对象

image-20230731213023846

  1. 客户端连接后,通过recv方法,接收客户端发送的消息

image-20230731213048654

  1. 通过conn(客户端当次连接对象),调用send方法可以回复消息

image-20230731213057314

  1. conn(客户端当次连接对象)和socket_server对象调用close方法,关闭连接
实现服务端并结合客户端进行测试

image-20230731213211183

下载网络调试助手作为客户端

https://github.com/nicedayzhu/netAssist/releases

image-20230731213230792

示例代码:

#演示Socket服务端开发import socket
#创造Socket对象
socket_server = socket.socket()
#修改ip地址和端口
socket_server.bind(("localhost", 8888))
#监听端口
socket_server.listen(1)
#listen 方法内接受一个整数传参数, 表示接受的链接数量
#等待客户端链接
#result: tuple = socket_server.accept()
#conn = result[0]    客户端和服务端的链接对象
#address = result[1]  客户端的地址信息
conn, address = socket_server.accept()
#accept方法返回的是二元元组(链接对象,客户端地址信息)
#可以通过 变量1, 变量2 = socket_server.accept()的形式,直接接受二元元组内的两个元素
#accept()方法,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一行不再向下执行print(f"我接收到了客户端的链接,客户端的信息是:{address}")while True:#接受客户端的信息,要使用客户端和服务端的本次链接对象,而非socket_server对象data: str = conn.recv(1024).decode("UTF-8")#recv接受的参数是缓冲区大小,一般1024即可#recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可通过decade方法通过UTF-8编码,将字节数组转换为字符串对象print(f"客户端发来的信息是:{data}")#发送回复消息msg = input("请输入你要和客户端回复的消息:")if msg == 'exit':breakconn.send(msg.encode("UTF-8"))#关闭链接
conn.close()
socket_server.close()

客户端开发

Socket客户端编程

主要分为如下几个步骤:

  1. 创建socket对象

image-20230731213335132

  1. 连接到服务端

image-20230731213341719

  1. 发送消息

image-20230731213347304

  1. 接收返回消息

image-20230731213408106

  1. 关闭链接

image-20230731213419783

服务端客户端相互通讯

结合上一节学习的服务端代码,以及当前学习的客户端代码。

两者均运行起来,进行相互通讯。

image-20230731213505005

正则表达式

基础匹配

正则表达式,又称规则表达式(Regular Expression),是使用单个字符串来描述、匹配某个句法规则的字符串,常被用来检索、替换那些符合某个模式(规则)的文本。

简单来说,正则表达式就是使用:字符串定义规则,并通过规则去验证字符串是否匹配。

比如,验证一个字符串是否是符合条件的电子邮箱地址,只需要配置好正则规则,即可匹配任意邮箱。

比如通过正则规则: (1+(.[\w-]+)*@[\w-]+(.[\w-]+)+$) 即可匹配一个字符串是否是标准邮箱格式

但如果不使用正则,使用if else来对字符串做判断就非常困难了。

正则的三个基础方法

Python正则表达式,使用re模块,并基于re模块中三个基础方法来做正则匹配。

分别是:match、search、findall 三个基础方法

  • re.match(匹配规则, 被匹配字符串)

从被匹配字符串开头进行匹配, 匹配成功返回匹配对象(包含匹配的信息),匹配不成功返回空。

image-20230731213638041

  • search(匹配规则, 被匹配字符串)

搜索整个字符串,找出匹配的。从前向后,找到第一个后,就停止,不会继续向后

image-20230731213915705

整个字符串都找不到,返回None

image-20230731213924313

  • findall(匹配规则, 被匹配字符串)

匹配整个字符串,找出全部匹配项

image-20230731213951142

找不到返回空list: []

image-20230731213957525

  1. re模块的三个主要方法
  • re.match,从头开始匹配,匹配第一个命中项
  • re.search,全局匹配,匹配第一个命中项
  • re.findall,全局匹配,匹配全部命中项

元字符匹配

在刚刚我们只是进行了基础的字符串匹配,正则最强大的功能在于元字符匹配规则。

单字符匹配

image-20230731214130317

示例:

字符串 s = “itheima1 @@python2 !!666 ##itcast3”

  • 找出全部数字:
re.findall(r‘\d’, s)

字符串的r标记,表示当前字符串是原始字符串,即内部的转义字符无效而是普通字符

  • 找出特殊字符:
re.findall(r‘\W’, s)
  • 找出全部英文字母:
re.findall(r’[a-zA-Z]’, s)

[]内可以写:[a-zA-Z0-9] 这三种范围组合或指定单个字符如[aceDFG135]

数量匹配

image-20230731214258248

边界匹配

image-20230731214320316

分组匹配

image-20230731214334658

递归

递归在编程中是一种非常重要的算法

递归: 即方法(函数)自己调用自己的一种特殊编程写法

如:

image-20230731214406613

函数调用自己,即称之为递归调用。

递归找文件

最典型的递归场景为找出一个文件夹中全部的文件。

如图,在D:/test 文件夹内,有如下嵌套结构和所属的文件, 可以通过递归编程的形式完成

image-20230731214440178

image-202307312144481853. os模块的3个方法

  • os.listdir,列出指定目录下的内容
  • os.path.isdir,判断给定路径是否是文件夹,是返回True,否返回False

  1. \w- ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/167072.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32F4_网络通信(网口)

前言 STM32F4开发板上自带了网口。可以通过开发板自带的网口和LWIP实现:TCP服务器、TCP客服端、UDP以及WEB服务器等四个功能。 1. STM32 以太网简介 STM32F4 芯片自带以太网模块,该模块包括带有专用 DMA 控制器的 MAC 802.3(介质访问控制&am…

计算机算法分析与设计(12)---贪心算法(最优装载问题和哈夫曼编码问题)

文章目录 一、最优装载问题1.1 问题表述1.2 代码编写 二、哈夫曼编码2.1 哈夫曼编码概述2.2 前缀码2.3 问题描述2.4 代码思路2.5 代码编写 一、最优装载问题 1.1 问题表述 1. 有一批集装箱要装上一艘载重量为 c c c 的轮船,已知集装箱 i ( 1 ≤ i ≤ n ) i(1≤i≤…

【Matlab】三维绘图函数汇总

本文用于汇总 Matlab 中的三维绘图函数。plot3() 函数用于绘制用参数方程表示的三维曲线。ezplot3() 函数用于三维曲线的符号绘图,需要用参数方程表示。mesh() 函数用于绘制三维曲面网格。surf() 函数用于绘制三维空间曲面。 目录 1. plot3() 2. ezplot3() 3. me…

R文件详细介绍、瘦身方案和原理

文章目录 1. 背景2. R文件介绍2.1 R文件概念2.1.1 标识符是怎么与资源联系起来的? 2.2 R文件内容2.3 library module和aar的R文件内容生成规则2.4 是谁生成的R文件?2.5 打包之后的R文件2.6 R文件为啥大?这么多? 3. 为什么R文件可以…

【Objective-C】浅析Block及其捕获机制

目录 Block的基本使用Block的声明Block的实现Block的调用 Block作为形参使用Block作为属性使用给Block起别名Block的copy Block的捕获机制auto类型的局部变量__block浅析static类型的局部变量全局变量 其他问题 Block的基本使用 什么是Block? Block (块…

2.2.C++项目:网络版五子棋对战之数据管理模块的设计

文章目录 一、数据管理模块实现(一)功能 二、设计(一)数据库设计(二)创建user_table类 一、数据管理模块实现 (一)功能 数据管理模块主要负责对于数据库中数据进行统一的增删改查管…

【快速解决】在vs2022中配置SFML图形库

目录 SFML 图形库的安装步骤如下: 1.下载 SFML 在 SFML 的官网(下载对应操作系统版本的 SFML)。​编辑 2.解压文件 将下载的压缩包解压至任意位置,得到类似如下的目录结构: 3.配置 VS 打开 Visual Studio&#xff…

人工智能、机器学习、深度学习的区别

人工智能涵盖范围最广,它包含了机器学习;而机器学习是人工智能的重要研究内容,它又包含了深度学习。 人工智能(AI) 人工智能是一门以计算机科学为基础,融合了数学、神经学、心理学、控制学等多个科目的交…

深度学习_3_实战_房价预测

梯度 实战 代码: # %matplotlib inline import random import torch import matplotlib.pyplot as plt # from d21 import torch as d21def synthetic_data(w, b, num_examples):"""生成 Y XW b 噪声。"""X torch.normal(0,…

Java EE-servlet API 三种主要的类

上述的代码如下: import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.i…

使用CMake构建一个简单的C++项目

文章目录 一. 构建一个简单的项目二. 构建过程1. 创建程序源文件2. 编写CMakeList.txt文件3. 构建项目并编译源代码 附件 一. 构建一个简单的项目 最基本的CMake项目是从单个源代码文件构建的可执行文件。对于像这样的简单项目,只需要一个包含三个命令的CMakeLists…

查看当前cmake版本支持哪些版本的Visual Studio

不同版本的的cmake对Visual Studio的版本支持不同,以下图示展示了如何查看当前安装的cmake支持哪些版本的Visual Studio。 1.打开cmake-gui 2.查看cmake支持哪些版本的Visual Studio

django基于Python的房价预测系统+爬虫+大屏可视化分析

欢迎大家点赞、收藏、关注、评论 文章目录 前言一、项目介绍二、开发环境三、功能需求分析1 数据采集功能设计2数据管理功能设计3爬虫功能需求分析4 数据可视化功能需求分析数据库表的设计 四、核心代码五、效果图六、文章目录 前言 房价是一个国家经济水平的重要体现&#xff…

正点原子嵌入式linux驱动开发——Linux并发与竞争

Linux是一个多任务操作系统,肯定会存在多个任务共同操作同一段内存或者设备的情况,多个任务甚至中断都能访问的资源叫做共享资源。在驱动开发中要注意对共享资源的保护,也就是要处理对共享资源的并发访问。在Linux驱动编写过程中对于并发控制…

2、Kafka 生产者

3.1 生产者消息发送流程 3.1.1 发送原理 在消息发送的过程中,涉及到了两个线程——main 线程和 Sender 线程。在 main 线程 中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator, Sender 线程不断从 RecordAccumulator 中…

为什么短信验证码要设置有效期?

安全性:验证码的主要目的是为了验证用户的身份,防止恶意或未经授权的访问。如果验证码没有有效期,恶意用户或攻击者可以获取验证码后无限期地尝试使用它。通过设置有效期,可以限制验证码的生命周期,提高系统的安全性。…

跳跃游戏Ⅱ-----题解报告

题目:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 与Ⅰ不同的是,这次要求找出最小的跳跃次数。思路也很简单,在每一次跳跃之后都更新最远的跳跃距离。 举个列子: 输入:2,3,1,1,4 第一次…

看我为了水作业速通C++!

和java不太一样的一样的标题打个*&#xff0c;方便对比 基本架构* #include<iostream> using namespace std; int main() { system("pause"); return 0; } 打印* cout << "需要打印的内容" <<endl endl 是一个特殊的输出流控…

【Java基础面试三十八】、请介绍Java的异常接口

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;请介绍Java的异常接口 …

JAVA高级教程-Java Map(6)

目录 6、Map的使用 6、Map的使用 package Map01;import java.util.HashMap; import java.util.Map; import java.util.Set;/*** Map接口的使用*/ public class Demo01_HashMap {public static void main(String[] args) {Map<String,String> mapnew HashMap<>();ma…