python高阶技巧一
闭包
简单认识一下闭包
以下代码,内层inner函数不仅依赖于自身的参数b,还依赖于外层outer函数的参数a。inner就是一个闭包函数,既能访问外部变量,又保证外部变量不是全局的,不会被篡改掉,确保了外部变量的安全。
-
def outer(a): -
def inner(b): -
print(f"<{a}>{b}<{a}>") -
return inner -
n1 = outer('程序员') # n1的类型是一个函数 -
n1('学习python') -
n1('学习java') -
n2 = outer('软件测试工程师') -
n2('功能测试') -
n2('自动化测试')

如果要在内层函数修改外层函数的变量,需要用nonlocal修饰,示例代码如下:
-
def outer(num1): -
def inner(num2): -
# 要对外层num1进行修改的话,需要nonlocal修饰 -
nonlocal num1 -
num1 += num2 -
print(num1) -
return inner -
fn = outer(10) -
fn(5) -
# 输出为15
'
运行
运行
案例:使用闭包方式简单实现ATM存取款
-
def account_create(initial_amount=0): -
def atm(num, deposit=True): -
nonlocal initial_amount -
if deposit: -
initial_amount += num -
print(f"存款:+{num},账户余额:{initial_amount}") -
else: -
if initial_amount<num: -
print(f"钱不够{num}了,取不出来!") -
else: -
initial_amount -= num -
print(f"取款:-{num},账户余额:{initial_amount}") -
return atm -
atm = account_create() -
atm(100, deposit=True) -
atm(500, deposit=True) -
atm(200, deposit=False) -
atm(1000, deposit=False)
'
运行
运行

闭包的优缺点:
优点:
无需定义全局变量即可实现通过函数,持续的访问、修改某个值
闭包使用的变量位于在函数内,难以被错误的调用修改
缺点:
由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存
装饰器
装饰器其实也是一种闭包,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能。
示例代码1:
-
def outer(func): -
def inner(): -
print("我要睡觉了......") -
func() -
print("睡醒了,我要起床了......") -
return inner() -
@outer # 相当于给sleep增加outer的装饰器 -
def sleep(): -
import random -
import time -
print("睡眠中......") -
time.sleep(random.randint(1, 5)) -
sleep()

示例代码2:
(1)代码实现:统计一个函数的运行时间:
-
import time -
# 统计一个函数的运行时间 -
def timer(func): -
def gf(): -
start_time = time.time() -
func() -
end_time = time.time() -
print("func运行的时间为:", end_time - start_time) -
return gf -
@timer -
def foo(): -
time.sleep(3) -
print("in foo") -
foo()

(2)被装饰函数带参数
import time
-
# 统计一个函数的运行时间 -
def timer(func): -
def gf(*args, **kwargs): -
start_time = time.time() -
func(*args, **kwargs) -
end_time = time.time() -
print("func运行的时间为:", end_time - start_time) -
return gf -
@timer -
def foo(name, age): -
time.sleep(3) -
print("in foo", name, age) -
foo("测试", 22)
(3)装饰器本身带参数
-
import time -
# 统计一个函数的运行时间 -
def timer(timer_type): -
print(timer_type) -
def outer(func): -
def inner(*args, **kwargs): -
start_time = time.time() -
func(*args, **kwargs) -
end_time = time.time() -
print("func运行的时间为:", end_time - start_time) -
return inner -
return outer -
@timer(timer_type='second') -
def foo(name, age): -
time.sleep(3) -
print("in foo", name, age) -
foo("测试", 22)
(4)被装饰函数有返回值
-
import time -
# 统计一个函数的运行时间 -
def timer(timer_type): -
print(timer_type) -
def outer(func): -
def inner(*args, **kwargs): -
start_time = time.time() -
res = func(*args, **kwargs) # 接收返回值 -
end_time = time.time() -
print("func运行的时间为:", end_time - start_time) -
return res # 返回 -
return inner -
return outer -
@timer(timer_type='second') -
def foo(name, age): -
time.sleep(3) -
print("in foo", name, age) -
return name # 被装饰函数返回name -
print(foo("测试", 22))
单例模式
背景
-
class Tool: -
pass -
t1 = Tool() -
t2 = Tool() -
print(t1) -
print(t2) -
# 输出结果: -
# <__main__.Tool object at 0x000001CEB2B190D0> -
# <__main__.Tool object at 0x000001CEB2B190A0>
通过print语句可以看出,它们的内存地址是不相同的,即t1和t2是完全独立的两个对象。
某些场景下,我们需要一个类无论获取多少次类对象,都仅仅提供一个具体的实例,用以节省创建类对象的开销和内存开销,比如某些工具类,仅需1个实例,即可在各处使用。
这就是单例模式所要实现的效果。
定义:
保证一个类只有一个实例,并提供一个访问它的全局访问点
适用场景:当一个类只能有一个实例,而客户可以从一个众所周知的访问点访问它
单例的实现模式:

工厂模式
背景:
当需要大量创建一个类的实例的时候,可以使用工厂模式即,从原生的使用类的构造去创建对象的形式迁移到,基于工厂提供的方法去创建对象的形式
-
class Person: -
pass -
class Worker(Person): -
pass -
class Student(Person): -
pass -
class Teacher(Person): -
pass -
worker = Worker() -
stu = Student() -
teacher = Teacher()
以上是传统方式构建基于Person的不同类对象。
采用工厂模式,代码就会变成如下:
-
class Person: -
pass -
class Worker(Person): -
pass -
class Student(Person): -
pass -
class Teacher(Person): -
pass -
class Factory: -
def get_person(self, p_type): -
if p_type == 'w': -
return Worker() -
elif p_type == 's': -
return Student() -
else: -
return Teacher() -
factory = Factory() -
worker = factory.get_person('w') -
stu = factory.get_person('s') -
teacher = factory.get_person('t')
使用工厂类的get_person()方法去创建具体的类对象优点:
大批量创建对象的时候有统一的入口,易于代码维护;
当发生修改,仅修改工厂类的创建方法即可;
符合现实世界的模式,即由工厂来制作产品(对象)
多线程编程(threading)
进程:就是一个程序,运行在系统之上,那么便称之这个程序为一个运行进程,并分配进程ID方便系统管理。
线程:线程是归属于进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位
并行执行:
多个进程同时在运行,即不同的程序同时运行,称之为: 多任务并行执行;
一个进程内的多个线程同时在运行,称之为:多线程并行执行;
写一段代码,我们先看下单线程运行下结果:
-
import time -
def sing(): -
while True: -
print("我在唱歌,啦啦啦......") -
time.sleep(1) -
def dance(): -
while True: -
print("我在跳舞,呱呱呱......") -
time.sleep(2) -
if __name__ == '__main__': -
sing() -
dance()

要想输出既在唱歌,又在跳舞,是无法满足的。
使用多线程的话,一个线程在唱歌,一个线程在跳舞,就可以满足需求。
语法:
import threading
thread_obj = threading.Thread([group [,target [,name [, args [,kwargs]]]]])
- group: 暂时无用,未来功能的预留参数
- target: 执行的目标任务名
- args: 以元组的方式给执行任务传参
- kwargs:以字典方式给执行任务传参
- name: 线程名,一般不用设置
启动线程,让线程开始工作thread_obi.start()
-
import time -
import threading -
def sing(): -
while True: -
print("我在唱歌,啦啦啦......") -
time.sleep(1) -
def dance(): -
while True: -
print("我在跳舞,呱呱呱......") -
time.sleep(2) -
if __name__ == '__main__': -
# 创建一个唱歌的线程 -
sing_thread = threading.Thread(target=sing) -
# 创建一个跳舞的线程 -
dance_thread = threading.Thread(target=dance) -
# 运行线程 -
sing_thread.start() -
dance_thread.start()

Socket服务端编程
主要分为如下几个步骤
1.创建socket对象
import socket
socket_server = socket.socket(0)
2.绑定socket_server到指定IP和地址
socket_server.bind(host, port)
3.服务端开始监听端口
socket_server.listen(backlog)
backlog为int整数,表示允许的连接数量,超出的会等待,可以不填,不填会自动设置一个合理值
4.接收客户端连接获得连接对象
conn.address = socket_server.accept()
print(f"接收到客户端连接,连接来自: {address}")
accept方法是阻塞方法,如果没有连接,会卡在当前这一行不向下执行代码
accept返回的是一个二元元组,可以使用上述形式,用两个变量接收二元元组的2个元素
5.客户端连接后,通过recv方法,接收客户端发送的消息
-
while True: -
data = conn.recv(1024).decode("UTF-8") -
# recv方法的返回值是字节数组(Bytes》,可以通过decode使用UTF-8解码为字符串 -
# recv方法的传参是buffsize,缓冲区大小,一般设置为1024即可 -
if data == 'exit': -
break -
print("接收到发送来的数据:",data) -
# 可以通过while True无限循环来持续和客户端进行数据交互 -
# 可以通过判定客户端发来的特殊标记,如exit,来退出无限循环
6.通过conn(客户端当次连接对象)调用send方法可以回复消息
-
while True: -
data = conn.recv(1024).decode("UTF-8") -
if data == 'exit': -
break -
print("接收到发送来的数据:", data) -
conn.send("你好呀哈哈哈".encode("UTF-8”))
7.conn(客户端当次连接对象)和socket_server对象调用close方法,关闭连接
Socket客户端编程
主要分为如下几个步骤:
1.创建socket对象
import socket
socket_client = socket.socket()
2.连接到服务端
socket_client.connect(("localhost",8888))
3.发送消息
-
while True: # 可以通过无限循环来确保持续的发送消息给服务端 -
send_msg = input("请输入要发送的消息") -
if send_msg == exit': -
# 通过特殊标记来确保可以退出无限循环 -
break -
socket_client.send(send_msg.encode("UTF-8")) # 消息需要编码为字节数组(UTF-8编码)
4.接收返回消息
-
while True: -
send_msg = input("请输入要发送的消息").encode("UTF-8") -
socket_client.send(send_msg) -
recv_data = socket_client.recv(124) # 1024是缓冲区大小,一般1024即可 -
#recv方法是阻塞式的,即不接收到返回,就卡在这里等待 -
print("服务端回复消息为:",recv_data.decode("UTF-8"))#接受的消息需要通过UTF-8解码为字符串
5.关闭链接
socket_client.close()
正则表达式
正则表达式,又称规则表达式(Regular Expression),是使用单个字符串来描述、匹配某个句法规则的字符串,常被用来检索、替换那些符合某个模式(规则)的文本。
简单来说,正则表达式就是使用: 字符串定义规则,并通过规则去验证字符串是否匹配。
三个基础方法:
使用re模块,并基于re模块(import re)中三个基础方法来做正则匹配。
(1)match
re.match(匹配规则,被匹配字符串)
从被匹配字符串开头进行匹配,匹配成功返回匹配对象(包含匹配的信息),匹配不成功返回空。
(2)search
re.search(匹配规则,被匹配字符串)
搜索整个字符串,找出匹配的。从前向后,找到第一个后,就停止,不会继续向后
(3)findall
re.findall(匹配规则,被匹配字符串)
匹配整个字符串,找出全部匹配项,找不到返回空list:[]
元字符匹配:
(1)单字符匹配:

实例:
-
import re -
s = "learn @@python3 12EEAA!!66 ##study3" -
# 找出全部数字 -
result1 = re.findall(r'\d', s) -
print(result1) # ['3', '1', '2', '6', '6', '3'] -
# 找出特殊字符 -
result2 = re.findall(r'\W', s) -
print(result2) # [' ', '@', '@', ' ', '!', '!', ' ', '#', '#'] -
# 找出全部英文字母 -
result3 = re.findall(r'[a-zA-Z]', s) -
print(result3) # ['l', 'e', 'a', 'r', 'n', 'p', 'y', 't', 'h', 'o', 'n', 'E', 'E', 'A', 'A', 's', 't', 'u', 'd', 'y']
(2)数量匹配:

(3)边界匹配:

(4)分组匹配

实例:
-
# 匹配账号,只能由字母和数字组成,长度限制6到10位 -
r1 = '^[0-9A-Za-z]{6,10}$' -
s1 = '12a3C6' -
print(re.findall(r1, s1)) # 输出['12a3C6'],证明匹配成功 -
# 匹配QQ号,要求纯数字,长度5-11,第一位不为0 -
r2 = '^[1-9][0-9]{4,10}$' -
s2 = '123456987' -
print(re.findall(r2, s2)) # 输出['123456987'],证明匹配成功 -
# 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址 -
r3 = r'(^[\w-]+(.[\w-]+)*@(qq|163|gmail)(.[\w-]+)+$)' -
s3 = '907218846@qq.com' -
print(re.match(r3, s3))
递归
概念:方法(函数)自己调用自己的一种特殊编程写法
案例:找出一个文件夹中全部的文件
-
import os -
def test_os(): -
# OS模块中的基础方法 -
# 将文件夹里面的内容显示出来 -
print(os.listdir("E:/python")) -
# 判断给的路径是不是个文件夹 -
print(os.path.isdir("E:/python/libs")) -
# 判断指定路径是否存在 -
print(os.path.exists("E:/python")) -
def get_file(path): -
file_list = [] -
if os.path.exists(path): -
for f in os.listdir(path): -
new_path = path + "/" + f -
if os.path.isdir(new_path): -
# 表明目录是文件夹不是文件,使用递归了 -
get_file(new_path) -
else: -
file_list.append(new_path) -
else: -
print(f"指定的目录{path}不存在") -
return [] -
return file_list -
if __name__ == '__main__': -
print(get_file("E:/python"))

感谢每一个认真阅读我文章的人!!!
作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

相关文章:
python高阶技巧一
闭包 简单认识一下闭包 以下代码,内层inner函数不仅依赖于自身的参数b,还依赖于外层outer函数的参数a。inner就是一个闭包函数,既能访问外部变量,又保证外部变量不是全局的,不会被篡改掉,确保了外部变量的…...
Java 对象头、Mark Word、monitor与synchronized关联关系以及synchronized锁优化
1. 对象在内存中的布局分为三块区域: (1)对象头(Mark Word、元数据指针和数组长度) 对象头:在32位虚拟机中,1个机器码等于4字节,也就是32bit,在64位虚拟机中࿰…...
鸿蒙网络编程系列50-仓颉版TCP回声服务器示例
1. TCP服务端简介 TCP服务端是基于TCP协议构建的一种网络服务模式,它为HTTP(超文本传输协议)、SMTP(简单邮件传输协议)等高层协议的应用程序提供了可靠的底层支持。在TCP服务端中,服务器启动后会监听一个或…...
软件测试基础(自动化测试、性能测试)
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 自动化测试的意义 缩短软件开发测试周期,可以让产品更快投放市场 测试效率高,充分利用硬件资源 节省人力资源,降低测试…...
C++中的原子操作:原子性、内存顺序、性能优化与原子变量赋值
一、原子操作与原子性 原子操作(atomic operation)是并发编程中的一个核心概念,指的是在多线程环境中,一个操作一旦开始,就不会被其他线程的操作打断,直至该操作完成。这种不可分割的特性保证了操作的原子…...
游戏引擎学习第19天
介绍 这段内容描述了开发者在进行游戏开发时,对于音频同步和平台层的理解和调整的过程。以下是更详细的复述: 开发者表达了他希望今天继续进行的工作内容。他提到,昨天他讲解了一些关于音频的内容,今天他想稍微深入讲解一下他正…...
RocketMQ: 专业术语以及相关问题解决
概述 要了解 RocketMQ 的多个关键特性的实现原理,并对消息中间件遇到的各种问题进行解决我们引用 JMS 规范 与 CORBA Notification 规范,规范为我们设计系统指明了方向但是仍有不少问题规范没有提及,对于消息中间件又至关重要RocketMQ 并不遵…...
C++ 类和对象中的 拷贝构造 和 运算符重载
构造函数中可以添加参数并添加默认值构成缺省构造,如果我们在构造函数的参数中加上自身类型类的引用和其他给出默认值的参数则会构成一种特殊的构造函数叫做———拷贝构造函数 1.拷贝构造 拷贝构造的特点: 1.拷贝构造函数是构造函数的一个重载 2.拷…...
el-table最大高度无法滚动
解决el-table同时使用fixed和计算的最大高度时固定右边的列无法跟随滚动的问题 原因:el-table组件会根据传入的 max-height 计算表格内容部分 和 fixed部分的最大高度,以此来生成滚动条和产生滚动效果,当传入的 max-height 为一个计算的高度…...
Vscode写markdown快速插入python代码
如图当我按下快捷键CRTLSHIFTK 自动出现python代码片段 配置方法shortcuts’ 打开这个json文件 输入 {"key": "ctrlshiftk","command": "editor.action.insertSnippet","when": "editorTextFocus","args&…...
基于 NCD 与优化函数结合的非线性优化 PID 控制
基于 NCD 与优化函数结合的非线性优化 PID 控制 1. 引言 NCD(Normalized Coprime Factorization Distance)优化是一种用于非线性系统的先进控制方法。通过将 NCD 指标与优化算法结合,可以在动态调整控制参数的同时优化控制器性能。此方法特别…...
【数据分析】基于GEE实现大津算法提取洞庭湖流域水体
大津算法提取水体 1.写在前面2.洞庭湖水体识别1.写在前面 最大类间方差法,也称为Otsu或大津法,是一种高效的图像二值化算法,由日本学者Otsu于1979年提出。该算法基于图像的频率分布直方图,假设图像包含两类像素(前景和背景),并计算出一个最佳阈值,以最大化类间方差,从…...
计算机网络安全 —— 报文摘要算法 MD5
一、报文摘要算法基本概念 使用加密通常可达到报文鉴别的目的,因为伪造的报文解密后一般不能得到可理解的内容。但简单采用这种方法,计算机很难自动识别报文是否被篡改。另外,对于不需要保密而只需要报文鉴别的网络应用,对整个…...
LeetCode 746. 使用最小花费爬楼梯 java题解
https://leetcode.cn/problems/min-cost-climbing-stairs/description/ 优化:可以不用dp数组,用变量,节省空间。 class Solution {public int minCostClimbingStairs(int[] cost) {int lencost.length;int[] dpnew int[len1];dp[0]0;//爬到0…...
Kubernetes的pod控制器
文章目录 一,什么是pod控制器二,pod控制器类型(重点)1.ReplicaSet2.Deployment3.DaemonSet4.StatefulSet5.Job6.Cronjob 三,pod与控制器的关系1.Deployment2.SatefulSet2.1StatefulSet组成2.2headless的由来2.3有状态服…...
ArcMap 处理栅格数据地形图配准操作
ArcMap 处理栅格数据地形图配准操作今天分享 一、地形图配准 1、绘图 点击 开始绘制,四条线 2、地理配准 1)点击弹出 2)画控制点 关闭自动校正 画线 从焦点向外划线,然后邮件输入坐标弹出框,填写相应内容,…...
comprehension
1.读题---猜---文章主题 只读题目,不读选项 2.文章--定位 3.用文章对应选项 1 be based on be dependent upon 2 fruitful adj.富有成效的;硕果累累的; 3 unfruitful adj.徒然的,无益的,没有结果的 4 desperately adv.拼命地&#x…...
开源宝藏:Smart-Admin 重复提交防护的 AOP 切面实现详解
首先,说下重复提交问题,基本上解决方案,核心都是根据URL、参数、token等,有一个唯一值检验是否重复提交。 而下面这个是根据用户id,唯一值进行判定,使用两种缓存方式,redis和caffeineÿ…...
使用 npm 安装 Electron 作为开发依赖
好的,下面是一个使用 npm pack 和 npm install 命令来打包和安装离线版本的 npm 包的具体示例。我们将以 electron 为例,演示如何在有网络连接的机器上打包 electron,然后在没有网络连接的机器上安装它。 步骤 1: 在有网络连接的机器上打包 …...
JavaWeb之综合案例
前言 这一节讲一个案例 1. 环境搭建 然后就是把这些数据全部用到sql语句中执行 2.查询所有-后台&前台 我们先写后台代码 2.1 后台 2.2 Dao BrandMapper: 注意因为数据库里面的名称是下划线分割的,我们类里面是驼峰的,所以要映射 …...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...
边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...
