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

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

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

闭包

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

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

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

如何解决?

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

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

"""
演示Python的闭包特性
"""

# 简单闭包
def outer(logo):

    def inner(msg):
        print(f"<{logo}>{msg}</{logo}>")
    return inner

fn1 = outer("好好学习")
fn1("小明")

fn1 = outer("天天向上")
fn1("小花")

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

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

"""
演示Python的闭包特性
"""

# 使用 nonlocal关键字修改外部函数的值
def outer(num1):

    def inner(num2):
        nonlocal num1
        num1 += num2
        print(num1)

    return inner

fn = 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_amount
        if deposit:
            initial_amount += num
            print(f"存款:+ {num}, 账户余额:{initial_amount}")
        else:
            initial_amount -= num
            print(f"取款:- {num}, 账户余额:{initial_amount}")

    return atm

atm = 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 inner

def sleep():
    import random
    import time
    print("睡眠中......")
    time.sleep(random.randint(1, 5))

fn = outer(sleep)
fn()

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

装饰器的语法糖写法

在这里插入图片描述

代码示例:

"""
演示装饰器的写法
"""

# 装饰器的快捷写法(语法糖)
def outer(func):
    def inner():
        print("我睡觉了")
        func()
        print("我起床了")

    return inner

@outer
def sleep():
    import random
    import time
    print("睡眠中......")
    time.sleep(random.randint(1, 5))

sleep()

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

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

设计模式

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

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

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

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

单例模式

在这里插入图片描述

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

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

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

"""
演示非单例模式的效果
"""

class StrTools:
    pass

s1 = StrTools()
s2 = StrTools()
print(s1)
print(s2)

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

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

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

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

class StrTools:
    pass

str_tool = StrTools()

test_str_tools.py

from str_tools_py import str_tool

s1 = str_tool
s2 = str_tool

print(s1)
print(s2)

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

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

工厂模式

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

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

优点:

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

代码示例:

"""
演示设计模式之工厂模式
"""
class Person:
    pass

class Worker(Person):
    pass

class Student(Person):
    pass

class Teacher(Person):
    pass

class 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 threading

def 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 threading

def 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':
        break
    conn.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':
        break
    conn.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 re

s = "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 os

def 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 + "/" + f
            if 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_list

if __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- ↩︎

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

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

相关文章

使用Java实现HTTP持久连接:一次与网络的“长聊“

大家都知道&#xff0c;传统的HTTP连接就像是一次性的餐具&#xff0c;每发送一个请求&#xff0c;就得重新建立一个连接&#xff0c;然后快速用完就扔。这对于网络资源来说&#xff0c;简直就是一场"大肆挥霍"的派对。但幸好&#xff0c;我们有HTTP持久连接&#xf…

【字符串】字典树

字典树就是利用一个这样的树状结构&#xff0c;可以记录字符串有没有出现过 放个板子 int nxt[100000][26], cnt; bool st[100000]; // 该结点结尾的字符串是否存在 void insert(string s, int l) // 插入字符串&#xff0c;l是字符串长度 { int p 0;for (int i 0; i < …

BGP邻居故障检测

第一种情况:如果AR2和AR4采用直连建立邻居,则排查步骤如下: 1)在AR2和AR4上使用ping x.x.x.x命令检查AR2和AR4用于建立EBGP邻居关系的直连地址连通性是否正常。如果不能ping通。则需要使用二分法从网络层向下层逐层进行排查,首先检查接口地址及路由的可达性,修改完成后,如…

Architecture Lab:Part C【流水线通用原理/Y86-64的流水线实现/实现IIADDQ指令】

目录 任务描述 知识回顾 流水线通用原理 Y86-64流水线实现&#xff08;PIPE-与PIPE&#xff09; 开始实验 IIADDQ指令的添加 优化 ncopy.ys 仅用第四章知识&#xff0c;CEP11.55 8x1展开&#xff0c;CPE9.35 8x1展开2x1展开消除气泡&#xff0c;CPE8.10 流水线化通过…

中小学信息学奥赛CSP-J认证 CCF非专业级别软件能力认证-入门组初赛模拟题一解析(选择题)

CSP-J入门组初赛模拟题一&#xff08;选择题&#xff09; 1、以下与电子邮件无关的网络协议是 A、SMTP B、POP3 C、MIME D、FTP 答案&#xff1a;D 考点分析&#xff1a;主要考查小朋友们网络相关知识的储备&#xff0c;FTP是文件传输协议和电子邮件无关&#xff0c;所以…

vscode debug无法直接查看eigen变量的问题(解决方法)

主要是给gdb添加一个Eigen相关的printer即可, 网上其他教程都搞太复杂了, 我整理成了一个仓库, 把仓库克隆下来直接运行 ./setup.sh脚本即可配置好 git clone gitgithub.com:fandesfyf/EigenGdb.git cd EigenGdb ./setup.sh 然后在vscode中重新debug即可。 效果 …

2.2-学成在线内容管理之课程分类查询+新增课程

文章目录 内容管理模块4 课程分类查询4.1 需求分析4.2 接口定义4.3 接口开发4.3.1 树型表查询4.3.2 开发Mapper 4.4 接口测试4.4.1 接口层代码完善4.4.2 测试接口 5 新增课程5.1 需求分析5.1.1 业务流程4.1.2 数据模型 5.2 接口定义5.3 接口开发5.3.1 保存课程基本信息5.3.2 保…

深度学习系列55:深度学习加速技术概述

总体有两个方向&#xff1a;模型优化 / 框架优化 1. 模型优化 1.1 量化 最常见的量化方法为线性量化&#xff0c;权重从float32量化为int8&#xff0c;将输入数据映射在[-128,127]的范围内。在 nvdia gpu&#xff0c;x86、arm 和 部分 AI 芯片平台上&#xff0c;均支持 8bit…

嵌入式系统中的电磁兼容和电磁干扰问题如何解决?

嵌入式系统在现代科技领域中发挥着越来越重要的作用&#xff0c;无论是在智能手机、汽车、医疗设备还是工业控制系统中&#xff0c;嵌入式系统都扮演着关键的角色。然而&#xff0c;随着嵌入式系统功能的不断扩展和集成度的增加&#xff0c;电磁兼容性(EMC)和电磁干扰(EMI)问题…

SpringBoot集成axis发布WebService服务

文章目录 1、使用maven-web项目生成server-config.wsdd文件1.1、新建maven-web项目1.1.1、新建项目1.1.2、添加依赖 1.2、编写服务接口和实现类1.2.1、OrderService接口1.2.2、OrderServiceImpl实现类 1.3、配置deploy.wsdd文件deploy.wsdd文件 1.4、配置tomcat1.4.1、配置tomc…

交友系统---让陌生人变成熟悉人的过程。APP小程序H5三端源码交付,支持二开。

随着社交网络的发展和普及&#xff0c;人们之间的社交模式正在发生着深刻的变革。传统的线下交友方式已经逐渐被线上交友取而代之。而同城交友正是这一趋势的产物&#xff0c;它利用移动互联网的便利性&#xff0c;将同城内的人们连接在一起&#xff0c;打破了时空的限制&#…

【node】Node.js的常用内置模块:

文章目录 一、os模块&#xff1a;【1】常用的OS模块方法包括&#xff1a;【2】案例&#xff1a; 二、path模块&#xff1a;【1】常用的path模块方法包括&#xff1a;【2】案例&#xff1a; 三、url模块&#xff1a;【1】常用的url模块方法包括&#xff1a;【2】案例&#xff1a…

LeetCode--代码详解 2.两数相加

2.两数相加 题目 难度&#xff1a;中等 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数…

数字孪生:智慧城市的核心技术与发展

一、引言 随着城市化进程的加速&#xff0c;智慧城市的概念和实践逐渐成为全球关注的焦点。智慧城市利用先进的信息通信技术&#xff0c;提升城市治理水平&#xff0c;改善市民的生活质量。而数字孪生作为智慧城市的核心技术&#xff0c;为城市管理、规划、应急响应等方面提供…

【数据分享】1929-2023年全球站点的逐日平均能见度(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;说到常用的降水数据&#xff0c;最详细的降水数据是具体到气象监测站点的降水数据&#xff01; 有关气象指标的监测站点数据&#xff0c;之前我们分享过1929-2023年全…

[Angular 基础] - 数据绑定(databinding)

[Angular 基础] - 数据绑定(databinding) 上篇笔记&#xff0c;关于 Angular 的渲染过程及组件的创建&简单学习&#xff1a;[Angular 基础] - Angular 渲染过程 & 组件的创建 Angular 之中的 databinding 是一个相对而言更加复杂&#xff0c;以及我个人觉得相对而言比…

《MySQL》超详细笔记

目录 基本知识 主流数据库 数据库基本概念 MySQL启动 数据库基本命令 数据库 启动数据库 显示数据库 创建数据库 删除数据库 使用数据库 查询当前数据库信息 显示数据库中的表 导入数据库脚本 表 查看表的结构 查看创建某个表的SQL语句 数据库的查询命令 查询…

设计模式学习笔记(一):基本概念;UML

文章目录 参考面向对象的设计原则创建型模式结构型模式行为型模式 UML视图图&#xff08;Diagram&#xff09;模型元素(Model Element)通用机制类之间的关系关联关系复杂&#xff01;&#xff01;聚合关系组合关系 依赖关系泛化关系接口与实现关系 参考 https://github.com/fa…

OpenCV/C++:点线面相关计算(二)

接续&#xff0c;继续更新 OpenCV/C:点线面相关计算_线面相交的点 代码计算-CSDN博客文章浏览阅读1.6k次&#xff0c;点赞2次&#xff0c;收藏12次。OpenCV处理点线面的常用操作_线面相交的点 代码计算https://blog.csdn.net/cd_yourheart/article/details/125626239 目录 1、…

Micro micro controller一览

https://www.microchip.com.cn/&#xff0c; Microchip中文网站 https://www.microchip.com.cn/newcommunity/index.php?mSearch&adosearch&moduleDownload&keyworddsPIC33&p3 Microcontrollers and microProcessors dsPIC33 Digital Signal Controllers (D…