查看原文
其他

工具&方法丨菜鸟升级打怪系列之python代码优化(1)

咪咪 数据Seminar 2021-06-03

我是前言


我叫"咪咪”,刚从浙江某高校统计专业毕业数月,目前就职于一家从事大数据开发创业公司的数据部门。平时的工作就是在 明明是直男但却经常喜欢“附庸风雅”的 技术主管带领下,用python处理各种数据抓取、数据挖掘和融合相关的问题。尽管在学校接触过一点python,但学习和实战完全是两回事。而且因为工作需要,我要一边学习提高、一边还要参与对经济类专业出身的实习生进行python培训,或者成为与其他部门经济类专业出身的同事进行数据需求沟通的“使者”。总之,工作数月,各种“酸爽”集于一身。如今,他们还怂恿我,让我将工作中各种“爱恨情仇”写下来,说是“给后来者留下点什么”。我不想把个人成长中碰到的各种“艰难困苦”公之于众,不过倒是可以将本人在工作中遇到的各种技术问题和解决的办法记录下来,留给未来终将成为“大咖”(他们说不想成为的大咖的菜鸟就不是“好菜鸟”-_-||)的我回忆之用,也能让后来的学弟学妹们多(少)学(受)点经(折)验(磨)。


密封线

     

我是正文


最近写备份文件代码的时候遇到了需要遍历出文件夹内所有文件以及文件夹的操作需求,只有遍历出文件夹下所有文件的路径才能上传到远程FTP。当时我就心头一紧,眉头一皱,想:这不就是之前公司内部培训时情景分析里出现过的吗!可是我忘记怎么做了怎么办!

最后只好默默翻出三个月前写的题目。嗯,这个名为“软著的苦恼”的情景分析题是小刘老师的风格无疑了!它大概长这样——


背景:小明最近被要求将自己的⼀个项目中的所有代码写⼊一个word文档中,面容逐渐憔悴,“又得做这么弱智的活了”,小明心想。但正如法国雕塑家罗丹所⾔,“生活中不是缺少美,而是缺少发现美的眼睛”,一件令人唾弃令人厌恶的事情,同样也有优雅的解决方案。我们作为Python的学习者,就应当有化腐朽为神奇的决心。


要求:请为小明写一段代码,允许他给出一个文件夹路路径,将这个文件夹内的所有.py,.html,.json文件中的内容全部写入word,并在每个文件内容之前附上文件名。


看完题目后,苦水突然从心底涌了上来,那时的我是一个只上过一次培训课的少年,绞尽脑汁写了一大段代码实现了遍历,沾沾自喜之余,小刘老师给我“泼了盆冷水”——他说用os库的walk方法只要三行!

问题理解其实并不难,最重要的就是获得目标文件夹内所有文件的路径,然后读取文件内容并写入word文档。不过在大多情况中,文件并不是单一的存在于一个文件夹下,而是以一个多级目录的形式存放文件(下图是本题示例文件夹的目录树)。因此,如何以迭代的形式遍历出目标文件夹下所有子文件的路径,是最关键的问题

┬──┬──work
│··├──┬──文件夹1
│··│··├─────文件夹3
│··│··├──文件131.py
│··│··└──文件132.html
│··├──文件11.py
│··├─────文件夹2
│··├──文件21.py
│··├──文件22.py
│··└──文件23.html
├──文件1.py
├──文件2.py
├──文件3.py
├──文件4.py
├──文件5.py
└──文件6.json

这个时候就要祭出我当时“呕心沥血”写出的代码了,因为os.listdir返回的结果最直观,直接返回当前文件夹下所有文件和文件夹列表。然而,令我手足无措的是os.listdir并不能遍历出子文件夹内的文件,思考再三,我只能通过构造两个列表,分别存放文件夹路径和文件路径,再使用pop函数取出文件夹列表中的最后一个文件夹路径,os.listdir列出该文件夹下的元素后再使用os.path.isfile判断元素是文件还是文件夹,如果是文件夹就继续放入文件夹列表中。为了重复完成这一系列动作,我还必须在外边加一个while循环。                 

# 使用os.listdir方法遍历文件夹
import os
# os.listdir返回结果示例
print(os.listdir(r'C:\Users\XFT User\Desktop\work'))
# ['文件1.py', '文件2.py', '文件3.py', '文件4.py', '文件5.py', '文件6.json', '文件夹1',
# '文件夹2']

file_list = []  # 文件列表
dir_list = [r'C:\Users\XFT User\Desktop\work']   # 文件夹列表  
while len(dir_list) != 0:                        
    test = dir_list.pop()  # 取出文件夹列表中最后一个元素
    content_list = os.listdir(test)   # 列出取出的文件夹内的所有文件或文件夹
    new_path = [os.path.join(test, filename) for filename in content_list]        
    for file in new_path:
        if os.path.isfile(file): # 判断当前文件夹下的内容是文件还是文件夹,若为文件,将该路径存入filepath中
            file_list.append(file)
       else:
            dir_list.append(file)  # 若是文件夹,将路径放入way列表中,下一个循环继续遍历
           
print(file_path)

或许菜鸟(大牛)们在读我前一段话和代码的时候已是一脸问号(嫌弃)。没关系,接下来os.walk方法将闪亮登场。

真正使用之前,一起先了解一下os.walk的功能,以及它能够为我们解决问题提供什么样的运行结果?能把代码优化到一个什么样的程度?

查看官方文档可以知道,os.walk返回的是一个三元素的元组,实际上是一个生成器,所以我们可以直接在for循环中对他们进行一一对应。运行代码,神奇的是——竟然只用三行代码就完成了文件夹遍历!

然后来看看返回的结果,由三个部分组成,大致是以目录树的形式呈现:

1.第一部分是string类型的文件根目录路径;

►2.第二部分是list类型的根目录下的文件夹列表;

►3.第三部分是list类型的根目录下的文件列表。

# 使用os.walk方法遍历文件夹
import os
import codecs
dir_path = r'C:\Users\XFT User\Desktop\work'
for path, dir_list, file_list in os.walk(dir_path):
    print(path, '&', dir_list, '&', file_list)C:\Users\XFT User\Desktop\work & ['文件夹1', '文件夹2'] & ['文件1.py', '文件2.py', '文件3.py', '文件4.py', '文件5.py', '文件6.json']
C:\Users\XFT User\Desktop\work\文件夹1 & ['文件夹3'] & ['文件11.py']
C:\Users\XFT User\Desktop\work\文件夹1\文件夹3 & [] & ['文件131.py', '文件132.html']
C:\Users\XFT User\Desktop\work\文件夹2 & [] & ['文件21.py', '文件22.py', '文件23.html']

有了上述结果为基础,回到题目中,我们使用for循环遍历文件夹中的文件名称(file_list内的元素)并使用os.path.join方法与根目录路径组合成文件路径。接下来只需要根据markdown的语法要求将读出的内容写入文档,使用Typora将md文档转化为word文档大功告成了!                                                                           

s_sum = ''
save_path = r'C:\Users\XFT User\Desktop\test.md'
for path, dir_list, file_list in os.walk(dir_path):
    for file_name in file_list: # 这里其实可以用列表生成式简化
        if os.path.splitext(file_name)[-1] in ('.py', '.json', '.html'): # 筛选出扩展名符合需求的文件
            file_path = os.path.join(path, file_name) # 生成文件路径
            print(file_path)
            # 读取文件
            with codecs.open(file_path, 'r', 'utf-8') as f:
                s = f.read()
            # 按Markdown语法整理字符串
            title = '# {}'.format(file_name) # Markdown中的一级标题的语法
            code = "```\n{}\n```".format(s) # Markdown中的代码语法
            # 拼接到与之前的内容上
            s_sum = "{}\n{}\n{}".format(s_sum, title, code)
           
with codecs.open(save_path, 'w', 'utf-8') as f:
    f.write(s_sum)

与之前菜鸟级的处理方式相比,第二种方法是不是很简单!os.walk方法不仅简化了代码,也可以使用for循环遍历文件夹名称与根目录组合成文件夹路径,我在写备份代码时也是需要在远程FTP上生成与本地对应的文件夹的,这个时候遍历出来的文件夹路径就派上用场了!

除了os.walk,os库中还有很多有关处理文件与目录的常用方法也很值得试一试!


我是后记


“纸上得来终觉浅”,当初写题目的时候还在疑惑这道题会有什么实际应用场景,没想到这么快就被我遇到了!学到的总会用得上的嘛~作为一只正在努力变成“大咖”的“菜鸟”,我很乐意向大家分享我的血泪成长史。且看咪咪我一路过关斩将如何修炼成功!敬请期待~



你要的工具&方法我都给你整理好了!

工具&方法丨老姚趣谈如何理解假设检验的逻辑

工具&方法 | 权威华人教授为您解惑:如何用好经济模型讲述“中国故事”?

工具&方法 | 小刘老师“再”出新招:JSON数据转为面板数据

工具&方法 | 教授教你如何用DID和DDD模型做政策评估

工具&方法 | 用Python3处理数据:“import”可以这样自由地调度函数?(内附代码)


听说你还在为数据呈现烦恼?看这里!

数据呈现丨想要数据可视化?你还少了它!

数据呈现 | Stata+R+Python:拨开数据迷雾,窥探可视化之“美”(工具书推荐,附PDF资源链接)

数据呈现 | Stata+R+Python:一文帮你解决Paper、PPT中的数据可视化问题


让我猜猜,或许你需要的还有这些!

特别推荐 | 专利引用数据,可以用来做哪些研究?

特别推荐 | 从股权投资视角看,山东省经济怎么了?

特别推荐 | 粤港澳大湾区企业发展研究系列报告之一重磅发布!




数据Seminar

这里是大数据、分析技术与学术研究的三叉路口


作者:企研数据 · 咪咪

审阅:企研数据 · Dyson

编辑:青酱



    欢迎扫描👇二维码添加关注    




    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存