Python学习路线 - Python高阶技巧 - 拓展

Python学习路线 - Python高阶技巧 - 拓展

    • 闭包
      • 闭包注意事项
    • 装饰器
      • 装饰器的一般写法(闭包写法)
      • 装饰器的语法糖写法
    • 设计模式
      • 单例模式
      • 工厂模式
    • 多线程
      • 进程、线程
      • 并行执行
      • 多线程编程
        • threading模块
    • 网络编程
      • Socket
      • 客户端和服务端
      • Socket服务端编程
        • 实现服务端并结合客户端进行测试
      • Socket客户端编程
    • 正则表达式
      • 正则表达式
      • 正则的三个基础方法
      • 元字符匹配
    • 递归
      • 递归找文件

闭包

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

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

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

如何解决?

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

在这里插入图片描述
在这里插入图片描述
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
在这里插入图片描述
简单闭包:
在这里插入图片描述
代码示例:

"""
演示Python的闭包特性
"""# 简单闭包
def outer(logo):def inner(msg):print(f"<{logo}>{msg}</{logo}>")return innerfn1 = outer("好好学习")
fn1("小明")fn1 = outer("天天向上")
fn1("小花")

输出结果:
在这里插入图片描述

修改外部函数变量的值:
在这里插入图片描述
代码示例:

"""
演示Python的闭包特性
"""# 使用 nonlocal关键字修改外部函数的值
def outer(num1):def inner(num2):nonlocal num1num1 += num2print(num1)return innerfn = outer(10)
fn(10)
fn(10)
fn(10)
fn(10)fn1 = outer(10)
fn1(10)

输出结果:
在这里插入图片描述
尝试实现以下atm取钱的闭包实现:
代码示例:

"""
演示Python的闭包特性
"""# 使用闭包实现ATM案例
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(100)
atm(200)
atm(100, deposit=False)

输出结果:
在这里插入图片描述

闭包注意事项

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

  • 无需定义全局变量即可实现通过函数,持续的访问、修改某个值
  • 闭包使用的变量的所用于在函数内,难以被错误的调用修改

缺点:

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

总结
1.什么是闭包
定义双层嵌套函数, 内层函数可以访问外层函数的变量
将内存函数作为外层函数的返回,此内层函数就是闭包函数
2.闭包的好处和缺点

  • 优点:不定义全局变量,也可以让函数持续访问和修改一个外部变量
  • 优点:闭包函数引用的外部变量,是外层函数的内部变量。作用域封闭难以被误操作修改
  • 缺点:额外的内存占用

3.nonlocal关键字的作用
在闭包函数(内部函数中)想要修改外部函数的变量值
需要用nonlocal声明这个外部变量

装饰器

装饰器其实也是一种闭包,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能
在这里插入图片描述
希望给sleep函数,增加一个功能:

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

在这里插入图片描述

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

在这里插入图片描述

代码示例:

"""
演示装饰器的写法
"""# 装饰器的一般写法(闭包)
def outer(func):def inner():print("我睡觉了")func()print("我起床了")return innerdef sleep():import randomimport timeprint("睡眠中......")time.sleep(random.randint(1, 5))fn = outer(sleep)
fn()

输出结果:
在这里插入图片描述

装饰器的语法糖写法

在这里插入图片描述

代码示例:

"""
演示装饰器的写法
"""# 装饰器的快捷写法(语法糖)
def outer(func):def inner():print("我睡觉了")func()print("我起床了")return inner@outer
def sleep():import randomimport timeprint("睡眠中......")time.sleep(random.randint(1, 5))sleep()

输出结果:
在这里插入图片描述

总结
1.什么是装饰器
装饰器就是使用创建一个闭包函数,在闭包函数内调用目标函数。
可以达到不改动目标函数的同时,增加额外的功能。
2.装饰器的写法
在这里插入图片描述

设计模式

设计模式是一种编程套路,可以极大的方便程序的开发。
最常见、最经典的设计模式,就是我们所学习的面向对象了。

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

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

设计模式非常多,我们主要挑选了2个经常用到的进行讲解。

单例模式

在这里插入图片描述

创建类的实例后,就可以得到一个完整的、独立的类对象。
通过print语句可以看出,它们的内存地址是不相同的,既t1和t2是完全独立的两个对象。
在这里插入图片描述

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

这就是单例模式所要实现的效果。
代码示例:

"""
演示非单例模式的效果
"""class StrTools:passs1 = StrTools()
s2 = StrTools()
print(s1)
print(s2)

输出结果:
在这里插入图片描述

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。
在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

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

单例的实现模式:
在这里插入图片描述
代码示例:
str_tools_py.py

class StrTools:passstr_tool = StrTools()

test_str_tools.py

from str_tools_py import str_tools1 = str_tool
s2 = str_toolprint(s1)
print(s2)

输出结果:
在这里插入图片描述
总结
1.什么是设计模式
设计模式就是一种编程套路。
使用特定的套路得到特定的效果
2.什么是单例设计模式
单例模式就是对一个类,只获取其唯一的类实例对象,持续复用它。

  • 节省内存
  • 节省创建对象的开销

工厂模式

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

  • 使用工厂类的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')

总结
1.什么是工厂模式
将对象的创建由使用原生类本身创建
转换到由特定的工厂方法来创建
2.好处
在这里插入图片描述

多线程

现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支持"多任务"的操作系统。
进程:就是一个程序,运行在系统之上,那么便称之这个程序为一个运行进程,并分配进程ID方便系统管理。
线程:线程是归属于进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位。

进程就好比一家公司,是操作系统对程序进行运行管理的单位
线程就好比公司的员工,进程可以有多个线程(员工),是进程实际的工作者

操作系统中可以运行多个进程,即多任务运行
一个进程内可以运行多个线程,即多线程运行
在这里插入图片描述

进程、线程

注意点:

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

线程之间是内存共享的,线程是属于进程的,一个进程内的多个线程之间是共享这个进程拥有的内存空间的。这就好比,公司员工之间是共享公司的办公场所。
在这里插入图片描述

并行执行

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

除了进程外,线程其实也是可以并行执行的。
也就是比如一个Python程序,其实是完全可以做到:

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

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

总结
1.什么是进程
程序在操作系统内运行,即成为一个运行进程
2.什么是线程
进程内部可以有多个线程,程序的运行本质上就是由进程内部的线程在实际工作的。
3.什么是并行执行

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

多线程编程

threading模块

绝大多数编程语言,都允许多线程编程,Python也不例外。
Python的多线程可以通过threading模块来实现。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
通过上图代码
即可实现多线程编程。

让一个Python程序实现启动2个线程
每个线程各自执行一个函数

代码示例:

"""
演示多线程编程的使用
"""
import time
import threadingdef sing():while True:print("我在唱歌,啦啦啦...")time.sleep(1)def dance():while True:print("我在跳舞,呱呱呱...")time.sleep(1)if __name__ == '__main__':# 创建一个唱歌的线程sing_thread = threading.Thread(target=sing)# 创建一个跳舞的线程dance_thread = threading.Thread(target=dance)# 让线程去干活sing_thread.start()dance_thread.start()

输出结果:
在这里插入图片描述
参数传递
需要传参的话可以通过:

  • args参数通过元组(按参数顺序)的方式传参
  • 或者使用kwargs参数用字典的形式传参

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码示例:

"""
演示多线程编程的使用
"""
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()

输出结果:
在这里插入图片描述

总结
1.threading模块的使用
thread_obj = threading.Thread(target=func) 创建线程对象
thread_obj.start() 启动线程执行
2.如何传参
在这里插入图片描述
在这里插入图片描述

网络编程

Socket

Socket(简称 套接字)是进程之间通信的一个工具,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,进程之间想要进行网络通信需要socket。
Socket负责进程之间的网络数据传输,好比数据的搬运工。
在这里插入图片描述
在这里插入图片描述
大多数软件都使用到了Socket进行网络通讯

客户端和服务端

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

Socket服务端:等待其它进程的连接、可接受发来的消息、可以回复消息
Socket客户端:主动连接服务端、可以发送消息、可以接收回复
在这里插入图片描述

Socket服务端编程

主要分为如下几个步骤:
1.创建socket对象
在这里插入图片描述

2.绑定socket_server到指定IP和地址
在这里插入图片描述

3.服务端开始监听端口
在这里插入图片描述

4.接收客户端连接,获得连接对象
在这里插入图片描述

5.客户端连接后,通过recv方法,接收客户端发送的消息
在这里插入图片描述

6.通过conn(客户端当次连接对象),调用send方法可以回复消息
在这里插入图片描述

7.conn(客户端当次连接对象)和socket_server对象调用close方法,关闭连接

实现服务端并结合客户端进行测试

在这里插入图片描述

下载网络调试助手作为客户端
https://github.com/nicedayzhu/netAssist/releases
在这里插入图片描述
在这里插入图片描述

代码示例:

"""
演示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}")# 接受客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象
data: str = conn.recv(1024).decode("UTF-8")
# recv接受的参数是缓冲区大小,一般给1024即可
# recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象
print(f"客户端发来的消息是:{data}")# 发送回复消息
msg = input("请输入你要和客户端回复的消息:").encode("UTF-8")
conn.send(msg)# 关闭连接
conn.close()
socket_server.close()

输出结果:
在这里插入图片描述
在这里插入图片描述

优化代码
代码示例:

"""
演示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对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象print(f"客户端发来的消息是:{data}")# 发送回复消息msg = input("请输入你要和客户端回复的消息:")if msg == 'exit':breakconn.send(msg.encode("UTF-8"))# 关闭连接
conn.close()
socket_server.close()

输出结果:
在这里插入图片描述
在这里插入图片描述

Socket客户端编程

主要分为如下几个步骤:
1.创建socket对象
在这里插入图片描述

2.连接到服务端
在这里插入图片描述

3.发送消息
在这里插入图片描述

4.接收返回消息
在这里插入图片描述

5.关闭链接
在这里插入图片描述

代码示例:
服务端

"""
演示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对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象print(f"客户端发来的消息是:{data}")# 发送回复消息msg = input("请输入你要和客户端回复的消息:")if msg == 'exit':breakconn.send(msg.encode("UTF-8"))# 关闭连接
conn.close()
socket_server.close()

客户端

"""
演示Socket客户端开发
"""
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务器
socket_client.connect(("localhost", 8888))while True:# 发送消息msg = input("请输入要给服务端发送的消息:")if msg == 'exit':break# 发送消息socket_client.send(msg.encode("UTF-8"))# 接收返回信息recv_data = socket_client.recv(1024)  # 1024是缓冲区的大小哦啊,一般1024即可,同样recv方法是阻塞的print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}")
# 关闭链接
socket_client.close()

输出结果:
在这里插入图片描述
在这里插入图片描述

正则表达式

正则表达式

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

简单来说,正则表达式就是使用:字符串定义规则,并通过规则去验证字符串是否匹配。
比如,验证一个字符串是否是符合条件的电子邮箱地址,只需要配置好正则规则,即可匹配任意邮箱。
比如通过正则规则:(^ [\w-]+(.[\w-]+)*@[\w-]+(.[\w-]+)+$) 即可匹配一个字符串是否是标准邮箱格式

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

正则的三个基础方法

Python正则表达式,使用re模块,并基于re模块中三个基础方法来做正则匹配。
分别是:match、search、findall三个基础方法

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

从被匹配字符串开头进行匹配,匹配成功返回匹配对象(包含匹配的信息),匹配不成功返回空。
在这里插入图片描述
在这里插入图片描述

  • search(匹配规则,被匹配字符串)
    搜索整个字符串,找出匹配的。从前向后,找到第一个后,就停止,不会继续向后
    在这里插入图片描述整个字符串都找不到,返回None
    在这里插入图片描述
  • findall(匹配规则,被匹配字符串)
    匹配整个字符串,找出全部匹配项
    在这里插入图片描述
    找不到返回空list:[]
    在这里插入图片描述
    代码示例:
"""
演示Python正则表达式re模块的3个基础匹配方法
"""
import res = "mry go start"
s1 = "1mry go start mry mry"
# match 从头匹配
result = re.match("mry", s)
print(result)
print(result.span())
print(result.group())result1 = re.match("mry", s1)
print(result1)# search 搜索匹配
result2 = re.search("mry", s1)
print(result2)
result3 = re.search("mry2", s1)
print(result3)# findall 搜索全部匹配
result4 = re.findall("mry", s1)
print(result4)

输出结果:
在这里插入图片描述

总结:
1.什么是正则表达式
是一种字符串验证的规则,通过特殊的字符串组合来确立规则
用规则去匹配字符串是否满足
如(1+(.[\w-]+)*@[\w-]+(.[\w-]+)+$)可以表示为一个标准邮箱的格式
2.re模块的三个主要方法

  • re.match,从头开始匹配,匹配第一个命中项
  • re.search,全局匹配,匹配第一个命中项
  • re.findall,全局匹配,匹配全部命中项

元字符匹配

在刚刚我们只是进行了基础的字符串匹配,正则最强大的功能在于元字符匹配规则。
单字符匹配:
在这里插入图片描述
示例:
字符串 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]

数量匹配
在这里插入图片描述

边界匹配
在这里插入图片描述

分组匹配
在这里插入图片描述

案例
1.匹配账号,只能由字母和数字组成,长度限制6到10位
规则为: 2{6, 10}$

2.匹配QQ号,要求纯数字,长度5-11,第一位不为0
规则为:3[0-9]{4, 10}&
[1-9]匹配第一位,[0-9]匹配后面4到10位

3.匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址
规则为:4+(.[\w-]+)*@(qq|163|gmail)(.[\w-]+)+&

4.[\w-]+ 表示出现a-z A-Z 0-9 _ 和 - 字符最少一个,最多不限

5.(.[\w-]+)*,表示出现组合 . 和 a-z A-Z 0-9 _ -的组合最少0次,最多不限

6.用于匹配:abc.ced.efg@123.com中的ced.efg这部分

  • @表示匹配@符号
  • (qq|163|gmail)表示只匹配这3个邮箱提供商
  • (.[\w-]+)+表示a-z A-Z 0-9 _ -的组合最少1次,最多不限

用于匹配abc.ced.efg@123.com.cn中的.com.cn这种
最后使用+表示最少一次,即比如:.com
多了可以是:.com.cn.eu这样

代码示例:

"""
演示Python正则表达式使用元字符进行匹配
"""
import re# 匹配账号,只能由字母和数字组成,长度限制610位
r = '^[0-9a-zA-Z]{6,10}'  # 正则表达式中多余的空格会导致正则规则失效
s = '1234567AsdeSd'
print(re.findall(r, s))# 匹配QQ号,需求纯数字,长度5~11,第一位不为0
r = '^[1-9][0-9]{4,10}$'
s = '012345678'
print(re.findall(r,s))# 匹配邮箱地址,只允许qq,163,gmail这三种邮箱地址
r = r'(^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$)'
s = 'a.b.c.d.e.f.gz@163.com.a.z.c.d.e'
print(re.findall(r,s))

输出结果:
在这里插入图片描述

总结
1.字符串的r标记表示,字符串内转移字符无效,作为普通字符使用
2.正则表达式的元字符规则
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

递归

递归在编程中是一种非常重要的算法
递归:即方法(函数)自己调用自己的一种特殊编程写法
如:
在这里插入图片描述
函数调用自己,即称之为递归调用。

那么,什么场景中会使用到递归呢?

递归找文件

最典型的递归场景为找出一个文件夹中全部的文件。
如图,在D:/test文件夹内,有如下嵌套结构和所属的文件,可以通过递归编程的形式完成
在这里插入图片描述
在这里插入图片描述

代码示例:

"""
演示Python递归操作
需求:通过递归,找出一个指定文件夹内的全部文件思路:写一个函数,列出文件夹内的全部内容,如果是文件就收集到list
如果是文件夹,就递归调用自己,再次判断。
"""
import osdef test_os():# 演示os模块的3个集成方法print(os.listdir("D:/test"))        # 列出路径下的内容print(os.path.isdir("D:/test/a"))   # 判断指定路径是不是文件夹print(os.path.exists("D:/test"))    # 判断指定路径是否存在def get_files_recursion_from_dir(path):"""从指定的文件夹中使用递归的方法,获取全部的文件列表:param path: 被判断的文件夹:return: 包含全部的文件,如果目录不存在或者五文件就返回一个空list"""file_list = []if os.path.exists(path):for f in os.listdir(path):new_path = path + "/" + fif os.path.isdir(new_path):# 进入到这里,表明这个目录是文件夹不是文件file_list += get_files_recursion_from_dir(new_path)else:file_list.append(new_path)else:print(f"指定的目录{path},不存在")return []return file_listif __name__ == '__main__':print(get_files_recursion_from_dir("D:/test"))

输出结果:
在这里插入图片描述
总结
1.什么是递归
在满足条件的情况下,函数自己调用自己的一种特殊编程技巧
2.递归需要注意什么?

  • 注意退出的条件,否则容易变成无限递归
  • 注意返回值的传递,确保从最内层,层层传递到最外层

3.os模块的3个方法

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

  1. \w- ↩︎

  2. 0-9a-zA-Z ↩︎

  3. 1-9 ↩︎

  4. \w- ↩︎

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

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

相关文章

华为豪掷770亿分红 至少将惠及14万人

华为技术有限公司近期发布的各项信息显示其在ICT领域的持续创新和稳健经营&#xff1a; 华为最近公布了2023年的分红方案&#xff0c;计划分红总额达770.85亿元&#xff0c;该分红将惠及14万员工&#xff0c;人均可获得约54.2万元1678910。此次分红的税后收益率是15.3%&#xf…

正则表达式与文本处理工具

目录 引言 一、正则表达式基础 &#xff08;一&#xff09;字符匹配 1.基本字符 2.特殊字符 3.量词 4.边界匹配 &#xff08;二&#xff09;进阶用法 1.组与引用 2.选择 二、命令之-----grep &#xff08;一&#xff09;基础用法 &#xff08;二&#xff09;高级用…

K8s 集群可观测性-数据分流最佳实践

简介 在微服务架构下&#xff0c;一个 k8s 集群中经常会部署多套业务&#xff0c;同时也意味着不同团队、不同角色、不同的业务会在同一集群中&#xff0c;需要将不同业务的数据在不同的空间进行管理和查看。 在传统的主机环境下&#xff0c;这个是可以通过不同的主机部署 Da…

百面嵌入式专栏(面试题)内存管理相关面试题1.0

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将介绍内存管理相关面试题 。 一、内存管理相关面试题 page数据结构中的_refcount和_mapcount有什么区别?匿名页面和高速缓存页面有什么区别?page数据结构中有一个锁,我们称为页锁,请问trylock_page()和loc…

协程模式在Android中的应用及工作原理

协程模式在Android中的应用及工作原理 在Android开发中&#xff0c;很多开发者通过代码模式学习协程&#xff0c;通常这已经足够应付了。但这种学习方式忽略了协程背后的精髓&#xff0c;事实上&#xff0c;它们的原理非常简单。那么&#xff0c;是什么使得这些模式起作用呢&a…

克魔助手 - iOS性能检测平台

前言 众所周知&#xff0c;如今的用户变得越来越关心app的体验&#xff0c;开发者必须关注应用性能所带来的用户流失问题。目前危害较大的性能问题主要有&#xff1a;闪退、卡顿、发热、耗电快、网络劫持等&#xff0c;但是做过iOS开发的人都知道&#xff0c;在开发过程中我们…

vue3+echarts:Vue中使用echarts从后端获取数据并赋值显示

//由于前后端交互,所以使用axios发送请求 const Count ref(null); //设备种类数值 const Name ref(null); //设备种类名称 //设备种类 饼图 const pieChart () > {const getpieChart echarts.init(document.getElementById("deviceKind"));// 创建图标getpieC…

使用 Matlab 拟合函数

1 加载数据 主页—>新建变量 粘贴 X 坐标&#xff0c;重命名变量名 同样的步骤&#xff0c;新建变量&#xff0c;加入 y 值 2 多项式拟合 打开APP&#xff0c;在数学工具里面选择--------》Curve Fitting 3 加载数据&#xff0c;选择功能

k8s中cert-manager管理https证书

前言 目前https是刚需,但证书又很贵,虽然阿里云有免费的,但没有泛域名证书,每有一个子域名就要申请一个证书,有效期1年,1年一到全都的更换,太麻烦了。经过搜索,发现了自动更新证书神器cert-manager;当然cert-manager是基于k8s的。 安装采用Helm方式 Chart地址: ht…

蓝桥杯刷题day06——平均

1、题目描述 有一个长度为n 的数组&#xff08;n 是 10 的倍数&#xff09;&#xff0c;每个数ai都是区间 [0,9] 中的整数。 小明发现数组里每种数出现的次数不太平均&#xff0c;而更改第i 个数的代价为bi&#xff0c; 他想更改若干个数的值使得这10 种数出现的次数相等&…

ArcGIS学习(五)坐标系-2

3.不同基准面坐标系之间的转换 在上一关中,我们学习了ArcGIS中的投影(投影栅格)工具,并以"WGS1984地理坐标系与WGS1984的UTM投影坐标系的转换”为例进行讲解。 "WGS1984地理坐标系与WGS1984的UTM投影坐标系的转换”代表的是同一个基准面下的两个坐标的转换。 …

微服务-微服务Alibaba-Nacos 源码分析 (源码流程图)-2.0.1

客户端注册临时实例&#xff0c;GRPC处理 客户端服务发现 及订阅处理 客户端数据变换&#xff0c;数据推送&#xff0c;服务端集群服务数据同步

vulhub中Adminer ElasticSearch 和 ClickHouse 错误页面SSRF漏洞复现(CVE-2021-21311)

Adminer是一个PHP编写的开源数据库管理工具&#xff0c;支持MySQL、MariaDB、PostgreSQL、SQLite、MS SQL、Oracle、Elasticsearch、MongoDB等数据库。 在其4.0.0到4.7.9版本之间&#xff0c;连接 ElasticSearch 和 ClickHouse 数据库时存在一处服务端请求伪造漏洞&#xff08…

20240206三次握手四次挥手

TCP和UDP异同点 相同点&#xff1a;同属于传输层的协议 不同点&#xff1a; TCP ----> 稳定 1> 提供面向连接的&#xff0c;可靠的数据传输服务 2> 传输过程中&#xff0c;数据无误、数据无丢失、数据无失序、数据无重复 1、TCP会给每个数据包编上编号&#xff…

计算机网络-华为无线网络配置

前面已经大致了解了无线通信的原理和无线组网的概念&#xff0c;今天来学习无线的配置过程与步骤。 一、无线组网配置流程 在开始配置前复习下前面讲过无线组网有涉及几个设备&#xff0c;AC无线控制器、AP无线接入点、POE交换机。无线组网与有线组网是相对独立的&#xff0c;不…

Python tkinter (15) —— PhotoImage

本文主要介绍Python tkinter PhotoImage图像应用及示例。 系列文章 python tkinter窗口简单实现 Python tkinter (1) —— Label标签 Python tkinter (2) —— Button标签 Python tkinter (3) —— Entry标签 Python tkinter (4) —— Text控件 Python tkinter (5) 选项按…

计算机网络-流量控制(数据链路层的流量控制及与传输层流量控制的区别 流量控制的方法 可靠传输,滑动窗口,流量控制三者关系)

文章目录 数据链路层的流量控制及与传输层流量控制的区别流量控制的方法各方法对应的发生窗口和接收窗口大小 可靠传输&#xff0c;滑动窗口&#xff0c;流量控制三者关系小结 数据链路层的流量控制及与传输层流量控制的区别 端到端&#xff1a;两个主机之间的 点对点&#xf…

idea设置terminal为git

要在IntelliJ IDEA中设置终端为Git Bash&#xff0c;请按照以下步骤操作&#xff1a; 打开 Settings&#xff08;设置&#xff09;。点击 Tools&#xff08;工具&#xff09;选项卡。进入 Terminal&#xff08;终端&#xff09;界面。在 Shell Path 下选择 Browse&#xff08;…

51单片机基础:定时器

1.定时器介绍 51单片机通常有两个定时器&#xff1a;定时器 0/1&#xff0c;好一点的可能有定时器3。 在介绍定时器之前我们先科普下几个知识&#xff1a; 1&#xff0c;CPU 时序的有关知识 ①振荡周期&#xff1a;为单片机提供定时信号的振荡源的周期&#xff08;晶振周期或…

golang 引入swagger(iris、gin)

golang 引入swagger&#xff08;iris、gin&#xff09; 在开发过程中&#xff0c;我们不免需要调试我们的接口&#xff0c;但是有些接口测试工具无法根据我们的接口变化而动态变化。文档和代码是分离的。总是出现文档和代码不同步的情况。这个时候就可以在我们项目中引入swagge…