我用Python写深度学习项目,用到最多的就是for循环遍历列表,但我一般是用AI辅助编程,对于AI生成的代码我只会大致理解其意思,并没有深入思考其内部逻辑。因为这个原因,这些代码使我不安,我写这篇博客的主要目的是通过对Python里一些常用函数用法的思考来加深对编程的理解。

一、os.walk()是什么

os.walk() 是Pythonos模块中用于遍历目录树的函数。它会递归地生成某个目录下所有子目录和文件的信息,适合做文件搜索、批量处理等操作。

二、函数签名

函数签名指的是函数的名字 + 参数信息(包括参数个数、顺序、名称、类型、默认值等),有时还包括返回值类型。它描述了调用函数所需的接口。换句话,函数前面就是函数的**“名片”**,让别人知道如何使用这个函数,而不需要关心函数内部是怎么实现的。

在Python中,签名主要包含函数名、参数,可选地包括类型注解和返回值类型。

在Python里,一个函数签名长这样:

def add(a: int, b: int = 0) -> int:
    return a + b

签名部分是这样的:

def add(a: int, b: int = 0) -> int

回到原来的话题,os.walk()函数的签名如下:

os.walk(top, topdown=True, onerror=None, followlinks=False)
  • top 要遍历的目录路径(字符串类型)

  • topdown(默认True

    • True: 先返回当前目录,再返回子目录(自顶向下遍历)。
    • False:先返回子目录,再返回当前目录(自低向上遍历)。
  • onerror 出现错误时的回调函数,一般用不到。

  • followlinks (默认False

    是否跟随符号链接(symlink)。如果设为True,可能会出现无限递归循环。

三、返回值

os.walk() 返回一个 生成器,每次迭代会得到一个三元组:

(dirpath,dirnames,filenames)
  • dirpath: 当前遍历到的目录路径(字符串)
  • dirnames: 当前目录下的所有子目录名(列表)。
  • filenames:当前目录下的所有子文件名(列表)。

四、基本用法

项目结构如下所示

processed_data
├── normal_data
│   ├── group_one
│   │   ├── table_one_normal.xlsx
│   │   ├── table_three_normal.xlsx
│   │   └── table_two_normal.xlsx
│   ├── group_three
│   │   ├── table_one_normal.xlsx
│   │   ├── table_three_normal.xlsx
│   │   └── table_two_normal.xlsx
│   └── group_two
│       ├── table_one_normal.xlsx
│       ├── table_three_normal.xlsx
│       └── table_two_normal.xlsx
└── patient
    ├── group_one
    │   ├── table_one.xlsx
    │   ├── table_three.xlsx
    │   └── table_two.xlsx
    ├── group_three
    │   ├── table_one.xlsx
    │   ├── table_three.xlsx
    │   └── table_two.xlsx
    └── group_two
        ├── table_one.xlsx
        ├── table_three.xlsx
        └── table_two.xlsx

我的遍历文件的代码如下:

for dirpath, dirnames, filenames in os.walk(root_dir):
    print("当前目录路径:", dirpath)
    print("子目录列表:", dirnames)
    print("文件列表:", filenames)

这是第一种写法,当我运行完脚本后得到的结果如下:

当前目录路径: ./processed_data/patient
子目录列表: ['group_one', 'group_three', 'group_two']
文件列表: []
当前目录路径: ./processed_data/patient/group_one
子目录列表: []
文件列表: ['table_two.xlsx', 'table_one.xlsx', 'table_three.xlsx']
当前目录路径: ./processed_data/patient/group_three
子目录列表: []
文件列表: ['table_two.xlsx', 'table_one.xlsx', 'table_three.xlsx']
当前目录路径: ./processed_data/patient/group_two
子目录列表: []
文件列表: ['table_two.xlsx', 'table_one.xlsx', 'table_three.xlsx']

从结果可以看到,一开始遍历时,dirpath代表是要遍历的根路径(root_dir),然后dirnames代表的是根路径下的子目录,这是一个列表,filenames应该是这个根目录下包含的文件,但当前根目录下只有子目录,没有文件,所以它是空的。

然后这个函数会一直遍历到包含文件的那个子目录,这时dirpath就代表的是包含最靠近文件的那个目录,dirname为空了(因为目录下没有其他目录了),filenames是目录下文件名的列表。

所以虽然是返回的的是三元组,但其实只表示两层含义:根目录及其子目录,或者根目录及其子文件。