python高阶技巧一

闭包

简单认识一下闭包

以下代码,内层inner函数不仅依赖于自身的参数b,还依赖于外层outer函数的参数a。inner就是一个闭包函数,既能访问外部变量,又保证外部变量不是全局的,不会被篡改掉,确保了外部变量的安全。

  1. def outer(a):

  2. def inner(b):

  3. print(f"<{a}>{b}<{a}>")

  4. return inner

  5. n1 = outer('程序员') # n1的类型是一个函数

  6. n1('学习python')

  7. n1('学习java')

  8. n2 = outer('软件测试工程师')

  9. n2('功能测试')

  10. n2('自动化测试')

image.png

如果要在内层函数修改外层函数的变量,需要用nonlocal修饰,示例代码如下:

  1. def outer(num1):

  2. def inner(num2):

  3. # 要对外层num1进行修改的话,需要nonlocal修饰

  4. nonlocal num1

  5. num1 += num2

  6. print(num1)

  7. return inner

  8. fn = outer(10)

  9. fn(5)

  10. # 输出为15

'

运行

运行

案例:使用闭包方式简单实现ATM存取款

  1. def account_create(initial_amount=0):

  2. def atm(num, deposit=True):

  3. nonlocal initial_amount

  4. if deposit:

  5. initial_amount += num

  6. print(f"存款:+{num},账户余额:{initial_amount}")

  7. else:

  8. if initial_amount<num:

  9. print(f"钱不够{num}了,取不出来!")

  10. else:

  11. initial_amount -= num

  12. print(f"取款:-{num},账户余额:{initial_amount}")

  13. return atm

  14. atm = account_create()

  15. atm(100, deposit=True)

  16. atm(500, deposit=True)

  17. atm(200, deposit=False)

  18. atm(1000, deposit=False)

'

运行

运行

image.png

闭包的优缺点:

优点:

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

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

缺点:

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

装饰器

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

示例代码1:

  1. def outer(func):

  2. def inner():

  3. print("我要睡觉了......")

  4. func()

  5. print("睡醒了,我要起床了......")

  6. return inner()

  7. @outer # 相当于给sleep增加outer的装饰器

  8. def sleep():

  9. import random

  10. import time

  11. print("睡眠中......")

  12. time.sleep(random.randint(1, 5))

  13. sleep()

image.png

示例代码2:

(1)代码实现:统计一个函数的运行时间:

  1. import time

  2. # 统计一个函数的运行时间

  3. def timer(func):

  4. def gf():

  5. start_time = time.time()

  6. func()

  7. end_time = time.time()

  8. print("func运行的时间为:", end_time - start_time)

  9. return gf

  10. @timer

  11. def foo():

  12. time.sleep(3)

  13. print("in foo")

  14. foo()

image.png

(2)被装饰函数带参数

import time
  1. # 统计一个函数的运行时间

  2. def timer(func):

  3. def gf(*args, **kwargs):

  4. start_time = time.time()

  5. func(*args, **kwargs)

  6. end_time = time.time()

  7. print("func运行的时间为:", end_time - start_time)

  8. return gf

  9. @timer

  10. def foo(name, age):

  11. time.sleep(3)

  12. print("in foo", name, age)

  13. foo("测试", 22)

(3)装饰器本身带参数

  1. import time

  2. # 统计一个函数的运行时间

  3. def timer(timer_type):

  4. print(timer_type)

  5. def outer(func):

  6. def inner(*args, **kwargs):

  7. start_time = time.time()

  8. func(*args, **kwargs)

  9. end_time = time.time()

  10. print("func运行的时间为:", end_time - start_time)

  11. return inner

  12. return outer

  13. @timer(timer_type='second')

  14. def foo(name, age):

  15. time.sleep(3)

  16. print("in foo", name, age)

  17. foo("测试", 22)

(4)被装饰函数有返回值

  1. import time

  2. # 统计一个函数的运行时间

  3. def timer(timer_type):

  4. print(timer_type)

  5. def outer(func):

  6. def inner(*args, **kwargs):

  7. start_time = time.time()

  8. res = func(*args, **kwargs) # 接收返回值

  9. end_time = time.time()

  10. print("func运行的时间为:", end_time - start_time)

  11. return res # 返回

  12. return inner

  13. return outer

  14. @timer(timer_type='second')

  15. def foo(name, age):

  16. time.sleep(3)

  17. print("in foo", name, age)

  18. return name # 被装饰函数返回name

  19. print(foo("测试", 22))

单例模式

背景

  1. class Tool:

  2. pass

  3. t1 = Tool()

  4. t2 = Tool()

  5. print(t1)

  6. print(t2)

  7. # 输出结果:

  8. # <__main__.Tool object at 0x000001CEB2B190D0>

  9. # <__main__.Tool object at 0x000001CEB2B190A0>

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

某些场景下,我们需要一个类无论获取多少次类对象,都仅仅提供一个具体的实例,用以节省创建类对象的开销和内存开销,比如某些工具类,仅需1个实例,即可在各处使用。

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

定义:

保证一个类只有一个实例,并提供一个访问它的全局访问点

适用场景:当一个类只能有一个实例,而客户可以从一个众所周知的访问点访问它

单例的实现模式:

image.png

工厂模式

背景:

当需要大量创建一个类的实例的时候,可以使用工厂模式即,从原生的使用类的构造去创建对象的形式迁移到,基于工厂提供的方法去创建对象的形式

  1. class Person:

  2. pass

  3. class Worker(Person):

  4. pass

  5. class Student(Person):

  6. pass

  7. class Teacher(Person):

  8. pass

  9. worker = Worker()

  10. stu = Student()

  11. teacher = Teacher()

以上是传统方式构建基于Person的不同类对象。

采用工厂模式,代码就会变成如下:

  1. class Person:

  2. pass

  3. class Worker(Person):

  4. pass

  5. class Student(Person):

  6. pass

  7. class Teacher(Person):

  8. pass

  9. class Factory:

  10. def get_person(self, p_type):

  11. if p_type == 'w':

  12. return Worker()

  13. elif p_type == 's':

  14. return Student()

  15. else:

  16. return Teacher()

  17. factory = Factory()

  18. worker = factory.get_person('w')

  19. stu = factory.get_person('s')

  20. teacher = factory.get_person('t')

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

大批量创建对象的时候有统一的入口,易于代码维护;

当发生修改,仅修改工厂类的创建方法即可;

符合现实世界的模式,即由工厂来制作产品(对象)

多线程编程(threading)

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

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

并行执行

多个进程同时在运行,即不同的程序同时运行,称之为: 多任务并行执行;

一个进程内的多个线程同时在运行,称之为:多线程并行执行;

写一段代码,我们先看下单线程运行下结果:

  1. import time

  2. def sing():

  3. while True:

  4. print("我在唱歌,啦啦啦......")

  5. time.sleep(1)

  6. def dance():

  7. while True:

  8. print("我在跳舞,呱呱呱......")

  9. time.sleep(2)

  10. if __name__ == '__main__':

  11. sing()

  12. dance()

image.png

要想输出既在唱歌,又在跳舞,是无法满足的。

使用多线程的话,一个线程在唱歌,一个线程在跳舞,就可以满足需求。

语法:

import threading

thread_obj = threading.Thread([group [,target [,name [, args [,kwargs]]]]])

  • group: 暂时无用,未来功能的预留参数
  • target: 执行的目标任务名
  • args: 以元组的方式给执行任务传参
  • kwargs:以字典方式给执行任务传参
  • name: 线程名,一般不用设置

启动线程,让线程开始工作thread_obi.start()

 
  1. import time

  2. import threading

  3. def sing():

  4. while True:

  5. print("我在唱歌,啦啦啦......")

  6. time.sleep(1)

  7. def dance():

  8. while True:

  9. print("我在跳舞,呱呱呱......")

  10. time.sleep(2)

  11. if __name__ == '__main__':

  12. # 创建一个唱歌的线程

  13. sing_thread = threading.Thread(target=sing)

  14. # 创建一个跳舞的线程

  15. dance_thread = threading.Thread(target=dance)

  16. # 运行线程

  17. sing_thread.start()

  18. dance_thread.start()

image.png

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方法,接收客户端发送的消息

 
  1. while True:

  2. data = conn.recv(1024).decode("UTF-8")

  3. # recv方法的返回值是字节数组(Bytes》,可以通过decode使用UTF-8解码为字符串

  4. # recv方法的传参是buffsize,缓冲区大小,一般设置为1024即可

  5. if data == 'exit':

  6. break

  7. print("接收到发送来的数据:",data)

  8. # 可以通过while True无限循环来持续和客户端进行数据交互

  9. # 可以通过判定客户端发来的特殊标记,如exit,来退出无限循环

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

 
  1. while True:

  2. data = conn.recv(1024).decode("UTF-8")

  3. if data == 'exit':

  4. break

  5. print("接收到发送来的数据:", data)

  6. 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.发送消息

 
  1. while True: # 可以通过无限循环来确保持续的发送消息给服务端

  2. send_msg = input("请输入要发送的消息")

  3. if send_msg == exit':

  4. # 通过特殊标记来确保可以退出无限循环

  5. break

  6. socket_client.send(send_msg.encode("UTF-8")) # 消息需要编码为字节数组(UTF-8编码)

4.接收返回消息

 
  1. while True:

  2. send_msg = input("请输入要发送的消息").encode("UTF-8")

  3. socket_client.send(send_msg)

  4. recv_data = socket_client.recv(124) # 1024是缓冲区大小,一般1024即可

  5. #recv方法是阻塞式的,即不接收到返回,就卡在这里等待

  6. 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)单字符匹配:

image.png

实例:

 
  1. import re

  2. s = "learn @@python3 12EEAA!!66 ##study3"

  3. # 找出全部数字

  4. result1 = re.findall(r'\d', s)

  5. print(result1) # ['3', '1', '2', '6', '6', '3']

  6. # 找出特殊字符

  7. result2 = re.findall(r'\W', s)

  8. print(result2) # [' ', '@', '@', ' ', '!', '!', ' ', '#', '#']

  9. # 找出全部英文字母

  10. result3 = re.findall(r'[a-zA-Z]', s)

  11. print(result3) # ['l', 'e', 'a', 'r', 'n', 'p', 'y', 't', 'h', 'o', 'n', 'E', 'E', 'A', 'A', 's', 't', 'u', 'd', 'y']

(2)数量匹配:

image.png

(3)边界匹配:

image.png

(4)分组匹配

image.png

实例:

 
  1. # 匹配账号,只能由字母和数字组成,长度限制6到10位

  2. r1 = '^[0-9A-Za-z]{6,10}$'

  3. s1 = '12a3C6'

  4. print(re.findall(r1, s1)) # 输出['12a3C6'],证明匹配成功

  5. # 匹配QQ号,要求纯数字,长度5-11,第一位不为0

  6. r2 = '^[1-9][0-9]{4,10}$'

  7. s2 = '123456987'

  8. print(re.findall(r2, s2)) # 输出['123456987'],证明匹配成功

  9. # 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址

  10. r3 = r'(^[\w-]+(.[\w-]+)*@(qq|163|gmail)(.[\w-]+)+$)'

  11. s3 = '907218846@qq.com'

  12. print(re.match(r3, s3))

递归

概念:方法(函数)自己调用自己的一种特殊编程写法

案例:找出一个文件夹中全部的文件

 
  1. import os

  2. def test_os():

  3. # OS模块中的基础方法

  4. # 将文件夹里面的内容显示出来

  5. print(os.listdir("E:/python"))

  6. # 判断给的路径是不是个文件夹

  7. print(os.path.isdir("E:/python/libs"))

  8. # 判断指定路径是否存在

  9. print(os.path.exists("E:/python"))

  10. def get_file(path):

  11. file_list = []

  12. if os.path.exists(path):

  13. for f in os.listdir(path):

  14. new_path = path + "/" + f

  15. if os.path.isdir(new_path):

  16. # 表明目录是文件夹不是文件,使用递归了

  17. get_file(new_path)

  18. else:

  19. file_list.append(new_path)

  20. else:

  21. print(f"指定的目录{path}不存在")

  22. return []

  23. return file_list

  24. if __name__ == '__main__':

  25. print(get_file("E:/python"))

image.png

 感谢每一个认真阅读我文章的人!!!

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

软件测试面试文档

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

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis最终篇分布式锁以及数据一致性

在前三篇我们几乎说完了Redis的所有的基础知识以及Redis怎么实现高可用性,那么在这一篇文章中的话我们主要就是说明如果我们使用Redis出现什么问题以及解决方案是什么,这个如果在未来的工作中也有可能会遇到,希望对看这篇博客的人有帮助,话不多说直接开干 一.Hotkey以及BigKey…

湘潭大学人工智能考试复习1(软件工程)

今年的试卷分值分布为&#xff1a; 选填40&#xff0c;两道计算题15x2 两道解答题15x2 复习重点&#xff1a; 1.人工智能学派派别 符号主义学派、连接主义学派、行为主义学派 各学派认知观&#xff1a; 符号主义&#xff08;逻辑主义、心理学派、计算机学派&#xff09;&am…

【蓝桥杯C/C++】深入解析I/O高效性能优化:std::ios::sync_with_stdio(false)

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: 蓝桥杯C/C 文章目录 &#x1f4af;前言&#x1f4af;C 语言与 C 语言的输入输出对比1.1 C 语言的输入输出1.2 C 语言的输入输出 &#x1f4af; std::ios::sync_with_stdio(false) 的作用与意义2.1 什么是 std::ios::sync_with_st…

GPT1.0 和 GPT2.0 的联系与区别

随着自然语言处理技术的飞速发展&#xff0c;OpenAI 提出的 GPT 系列模型成为了生成式预训练模型的代表。作为 GPT 系列的两代代表&#xff0c;GPT-1 和 GPT-2 虽然在架构上有着继承关系&#xff0c;但在设计理念和性能上有显著的改进。本文将从模型架构、参数规模、训练数据和…

嵌入式系统与OpenCV

目录 一、OpenCV 简介 二、嵌入式 OpenCV 的安装方法 1. Ubuntu 系统下的安装 2. 嵌入式 ARM 系统中的安装 3. Windows10 和树莓派系统下的安装 三、嵌入式 OpenCV 的性能优化 1. 介绍嵌入式平台上对 OpenCV 进行优化的必要性。 2. 利用嵌入式开发工具&#xff0c;如优…

戴尔 AI Factory 上的 Agentic RAG 搭载 NVIDIA 和 Elasticsearch 向量数据库

作者&#xff1a;来自 Elastic Hemant Malik, Dell Team 我们很高兴与戴尔合作撰写白皮书《戴尔 AI Factory with NVIDIA 上的 Agentic RAG》。白皮书是一份供开发人员参考的设计文档&#xff0c;概述了实施 Agentic 检索增强生成 (retrieval augmented generation - RAG) 应用…

特征交叉-MaskNet文章总结代码实现

MaskNet 这个模型是微博21年提出的&#xff0c;23年twitter(X)开源的推荐系统排序模块使用的backbone结构。 核心思想是认为DNN为主的特征交叉是addictive&#xff0c;交叉效率不高&#xff1b;所以设计了一种multiplicatvie的特征交叉 如何设计muliplicative特征交叉呢&#x…

GRU (门控循环单元 - 基于RNN - 简化LSTM又快又好 - 体现注意力的思想) + 代码实现 —— 笔记3.5《动手学深度学习》

目录 0. 前言 1. 门控隐状态 1.1 重置门和更新门 1.2 候选隐状态 1.3 隐状态 2. 从零开始实现 2.1 初始化模型参数 2.2 定义模型 2.3 训练与预测 3 简洁实现 4. 小结 0. 前言 课程全部代码&#xff08;pytorch版&#xff09;已上传到附件看懂上一篇RNN的所有细节&am…

Java 基于SpringBoot+vue框架的老年医疗保健网站

大家好&#xff0c;我是Java徐师兄&#xff0c;今天为大家带来的是Java Java 基于SpringBootvue框架的老年医疗保健网站。该系统采用 Java 语言开发&#xff0c;SpringBoot 框架&#xff0c;MySql 作为数据库&#xff0c;系统功能完善 &#xff0c;实用性强 &#xff0c;可供大…

JavaWeb-表单-07

表单标签 介绍 code: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>HTML-表单</title> &…

计算机网络socket编程(4)_TCP socket API 详解

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络socket编程(4)_TCP socket API 详解 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&…

向量数据库FAISS之五:原理(LSH、PQ、HNSW、IVF)

1.Locality Sensitive Hashing (LSH) 使用 Shingling MinHashing 进行查找 左侧是字典&#xff0c;右侧是 LSH。目的是把足够相似的索引放在同一个桶内。 LSH 有很多的版本&#xff0c;很灵活&#xff0c;这里先介绍第一个版本&#xff0c;也是原始版本 Shingling one-hot …

Django启用国际化支持(2)—实现界面内切换语言:activate()

文章目录 ⭐注意⭐1. 配置项目全局设置&#xff1a;启用国际化2. 编写视图函数3. 配置路由4. 界面演示5、扩展自动识别并切换到当前语言设置语言并保存到Session设置语言并保存到 Cookie ⭐注意⭐ 以下操作依赖于 Django 项目的国际化支持。如果你不清楚如何启用国际化功能&am…

【初阶数据结构与算法】线性表之栈的定义与实现(含源码和有效的括号练习)

文章目录 一、栈的概念与结构1.栈的概念与操作2.栈的底层结构选型 二、栈的实现1.栈结构的定义2. 栈的初始化和销毁栈的初始化栈的销毁 3.栈的扩容与入栈栈的扩容入栈 4.判断栈是否为空和出栈判断栈是否为空出栈 5.取栈顶元素和获取栈中有效元素个数取栈顶元素获取栈中有效元素…

基于Spring Boot+Unipp的博物馆预约小程序(协同过滤算法、二维码识别)【原创】

&#x1f388;系统亮点&#xff1a;协同过滤算法、二维码识别&#xff1b; 一.系统开发工具与环境搭建 1.系统设计开发工具 后端使用Java编程语言的Spring boot框架 项目架构&#xff1a;B/S架构 运行环境&#xff1a;win10/win11、jdk17 前端&#xff1a; 技术&#xff1a;框…

Python 快速入门(上篇)❖ Python基础知识

Python 基础知识 Python安装**运行第一个程序:基本数据类型算术运算符变量赋值操作符转义符获取用户输入综合案例:简单计算器实现Python安装** Linux安装: yum install python36 -y或者编译安装指定版本:https://www.python.org/downloads/source/ wget https://www.pyt…

【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段

文章目录 一、MyBatis-Plus简介二、快速入门1、环境准备2、将mybatis项目改造成mybatis-plus项目&#xff08;1&#xff09;引入MybatisPlus依赖&#xff0c;代替MyBatis依赖&#xff08;2&#xff09;配置Mapper包扫描路径&#xff08;3&#xff09;定义Mapper接口并继承BaseM…

【人工智能】PyTorch、TensorFlow 和 Keras 全面解析与对比:深度学习框架的终极指南

文章目录 PyTorch 全面解析2.1 PyTorch 的发展历程2.2 PyTorch 的核心特点2.3 PyTorch 的应用场景 TensorFlow 全面解析3.1 TensorFlow 的发展历程3.2 TensorFlow 的核心特点3.3 TensorFlow 的应用场景 Keras 全面解析4.1 Keras 的发展历程4.2 Keras 的核心特点4.3 Keras 的应用…

Chrome 浏览器 131 版本新特性

Chrome 浏览器 131 版本新特性 一、Chrome 浏览器 131 版本更新 1. 在 iOS 上使用 Google Lens 搜索 自 Chrome 126 版本以来&#xff0c;用户可以通过 Google Lens 搜索屏幕上看到的任何图片或文字。 要使用此功能&#xff0c;请访问网站&#xff0c;并点击聚焦时出现在地…

2.不同语音ai任务dataset类写法

主流语音任务 语音数据读取基本原则 直接保存语音会将该对象保存在内存中&#xff08;Dataset类调用__getitem__方法&#xff09; 所以一般保存这些数据的存储路径文档&#xff08;表单&#xff09;而不是数据的直接copy&#xff08;不然占用内存太大了&#xff09; 通常用nump…