实例中学习python的walk/map/filter/lambda
背景
编程语言只有在实际使用中才能积累实战经验,才能真正掌握。从寻找特定文件夹中寻找特定后缀名的文件列表是一个很常用的场景,可以扩展到将找到的(符合条件的)文件列表做重命名、删除、备份等操作。我们本次就从此实例出发,去学习python语言中的walk/map/filter/lambda函数的使用。
我们测试环境的当前目录下除了两个代码文件:jsj_xx_1.py和jsj_xx_2.py,其余都是测试相关的目录和文件,具体如下:
实例的需求是找到当前目录下的后缀名为“.name1”和“.name2”的文件。开始吧,搞懂我们的示例代码(2个.py文件),就大致就掌握了walk/map/filter/lambda这些函数啦!
我们分别使用os.path.walk和os.walk去实现,学习这两个看似很混淆的函数。
使用os.path.walk
使用os.path.walk的话,我们(计算机学习微信公众号:jsj_xx)的代码(jsj_xx_1.py)如下:(请参考注释)
import os
# author: jsj_xx
def find_filter_files(dir_list, name):
# 保存结果的列表,用于输出
found_file_list = []
# 对指定目录(dirname)处理,该目录下的文件和子目录都在list_of_dir列表里,
# 处理(包括过滤子目录和过滤一些文件)后的结果保存到found_file_list里# 0)使用lambda定义一个简单的合成完整路径的匿名函数,其中a就是list_of_dir中的元素
# 1)map用来将list_of_dir列表里的所有元素加上完整路径名
# 2)第二个filter用来过滤掉所有的子目录
# 3)第一个filter用来过滤掉不符合后缀名条件的文件
# 4)最后通过extend将符合条件的文件存放到found_file_list列表里
def filter_name_func(found_file_list, dirname, list_of_dir):
found_file_list.extend(\
filter(lambda a: os.path.splitext(a)[1] in name,\
filter(os.path.isfile,\
map(lambda a: os.path.join(dirname, a), list_of_dir))))
def func(one_dir):
# path.walk对一个目录做处理,
# 对该目录下的每个子目录和文件都会调用
# filter_name_func做处理,
# 对目录的每个子目录又会递归如上的处理。os.path.walk(one_dir, filter_name_func, found_file_list)
# 遍历dir_list列表,以每一个元素(比如dir1目录)
# 作为入参去调用函数funcmap(func, dir_list)
return found_file_list
if __name__ == '__main__':
print "found files: "+" ".join(find_filter_files(['dir1','dir2'], [".name1", ".name2"]))
运行结果:(找出dir1和dir2两个目录下的后缀名为“.name1”或者“.name2”的文件)
jsj_xx$ python jsj_xx_1.py
found files: dir1/1.name1 dir2/2.name2
下面是pydoc对os.path.walk的讲解:
walk(top, func, arg)
Directory tree walk with callback function.
For each directory in the directory tree rooted at top (including top
itself, but excluding '.' and '..'), call func(arg, dirname, fnames).
dirname is the name of the directory, and fnames a list of the names of
the files and subdirectories in dirname (excluding '.' and '..').
可见,对于示例代码中的filter_name_func,它里面的dirname是当前处理的目录(比如“dir1”或者“dir2/dir3”)。而list_of_dir则是该目录下的所有文件和子目录('.'和’..'除外),没有做区分。
使用os.walk
如果使用os.walk,我们(计算机学习微信公众号:jsj_xx)的代码(jsj_xx_2.py)如下:(请参考注释)
import os
# author: jsj_xx
def find_filter_files(dir,name):
found_file_list = []
# 将每个需要处理的目录(parent_dirname)下的文件和子目录区分对待
# 文件列表存放到list_of_dir里,子目录列表存放在dirname里
# 其它部分代码参考jsj_xx_1.py即可
for parent_dirname,dirname,list_of_dir in os.walk(dir):
found_file_list.extend(\
filter(lambda a: os.path.splitext(a)[1] in name,\
filter(os.path.isfile,\
map(lambda a: os.path.join(parent_dirname, a), list_of_dir))))
return found_file_list
if __name__ == '__main__':
print "found files: "+" ".join(find_filter_files('.',['.name1', '.name2']))
运行结果:(找出当前目录下的后缀名为“.name1”或者“.name2”的文件)
jsj_xx$ python jsj_xx_2.py
found files: ./dir1/1.name1 ./dir2/2.name2
下面是pydoc对os.walk的讲解:
walk(top, topdown=True, onerror=None, followlinks=False)
Directory tree generator.
For each directory in the directory tree rooted at top (including top
itself, but excluding '.' and '..'), yields a 3-tuple
dirpath, dirnames, filenames
dirpath is a string, the path to the directory. dirnames is a list of
the names of the subdirectories in dirpath (excluding '.' and '..').
filenames is a list of the names of the non-directory files in dirpath.
Note that the names in the lists are just names, with no path components.
To get a full path (which begins with top) to a file or directory in
dirpath, do os.path.join(dirpath, name).
可见,对于示例代码中的os.walk,parent_dirname是处理的目录,dirname是其下的所有子目录('.'和’..'除外),而list_of_dir则是其下的所有文件,(对parent_dirname目录下的文件和子目录)做了区分。
总结
os.path.walk没有对处理目录下的文件和子目录做区分,直接交给回调函数处理(内部可以再去区分),而os.walk是区分的。另外,os.path.walk是不需要循环迭代每个目录(通过循环迭代回调函数来隐式实现),而os.walk需要显式循环迭代每个目录。通过实例,我们也大致掌握了map/filter/lambda函数的用法。
来自:http://mp.weixin.qq.com/s?__biz=MzAxNjM3MDkyOQ==&mid=205165830&idx=1&sn=de5010c54f96b5ea0a456a41d1603c30