Python的递归,几种炫技的用法

Python的递归,几种炫技的用法

有个学员在提问python的递归实现,具体题目是用递归的方式,实现指定目录下面所有文件的size统计。自己写了写,发现这个题目还挺有意思的。

代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from multiprocessing.dummy import Pool as ThreadPool
import os


# 我自己写各种python代码的一个目录,你没看错,我平时用Linux办公,因为逼格高 ʅ(´◔౪◔)ʃ
path = "/home/david/Code/Python"


def dir_size(d):
    """
    递归版本.

    这是最基础的版本,没啥好说的,需要注意的是,既然用递归,
    就不要考虑全局变量啥的了,累计的size,直接作为返回值就好了。
    """
    # 读取文件信息
    dlist = os.listdir(d)
    # 遍历所有内容
    allsize = 0
    for i in dlist:
        # 为遍历的文件添加目录
        file = os.path.join(d, i)
        # 判断是否是文件
        if os.path.isfile(file):
            m = os.path.getsize(file)
            allsize += m
        # 判断是否是目录
        if os.path.isdir(file):
            # 调用自己
            allsize += dir_size(file)
    return allsize


print('dir size:\t{}'.format(dir_size(path)))


def dir_size(d):
    """
    递归comprehension版本.

    这个是逼格稍微高一点的版本,这里的重点就是comprehension了。
    """
    dlist = [os.path.join(d, i) for i in os.listdir(d)]
    allsize = sum([os.path.getsize(file)
                   for file in dlist if os.path.isfile(file)])

    allsize += sum([dir_size(file)
                    for file in dlist if os.path.isdir(file)])

    return allsize


print('dir size:\t{}'.format(dir_size(path)))


def dir_size(d):
    """
    递归comprehension版本.

    另一种蛋疼的写法, 吓唬人玩行,一般别吃饱了撑的用这种写法.
    """
    return sum([dir_size(f) if os.path.isdir(f) else os.path.getsize(f)
                for f in [os.path.join(d, i) for i in os.listdir(d)]])


print('dir size:\t{}'.format(dir_size(path)))


def dir_size(d):
    """
    递归map filter版本.

    简洁的一逼,刚开始没想起来。
    """
    dlist = [os.path.join(d, i) for i in os.listdir(d)]
    allsize = sum(map(os.path.getsize, filter(os.path.isfile,    dlist)))
    allsize += sum(map(dir_size, filter(os.path.isdir,    dlist)))

    return allsize


print('dir size:\t{}'.format(dir_size(path)))


def dir_size(d):
    """
    多线程递归版本.

    1,在这里,这个版本反而比单线程的慢,因为我本地是SSD,而且目录也没有大到离谱,线程切换的
        开销已经完全抵消了多线程的IO效率优势。如果是统计NFS,大规模的磁盘阵列啥的,可能多线程
        会有一些微薄的优势。

    2,因为有递归,所以不能用多进程。python里面的子进程不能再有子进程,会报错的。不要在有递归
        的场合使用多进程,除非小心的设计一下。
        这里其实还有一种思路是先用walk列出所有的文件目录,再用多线程或者多进程统计文件大小,但
        是列出所有目录这个动作本身就要遍历所有文件了,所以这种做法在这个场景下其实效率不高。
    """
    dlist = [os.path.join(d, i) for i in os.listdir(d)]
    allsize = sum([os.path.getsize(file)
                   for file in dlist if os.path.isfile(file)])
    p = ThreadPool()

    ret = p.map(dir_size, [file for file in dlist if os.path.isdir(file)])
    p.close()
    p.join()
    allsize += sum(ret)

    return allsize


print('dir size:\t{}'.format(dir_size(path)))


def dir_size(d):
    """
    walk版本.

    这个版本就没有递归了,有点离题,但是递归这个东西本身就有点反人类。
    没想起来怎么把walk的循环用comprehension代替,有兴趣的亲可以试一下。
    """
    allsize = 0
    for r, ds, fs in os.walk(d):
        allsize += sum(os.path.getsize(file) for
                       file in [os.path.join(r, f) for f in fs])
    return allsize


print('dir size:\t{}'.format(dir_size(path)))

总结

忘了哪里看到得了,python里面,尽量避免for/while循环的使用,if判断也尽量少用,这样不仅代码更简洁,代码的运行效率也会更高(目前没觉得)。

Python里面有很多很方便的用法,部分支持函数式编程。跟java/C++之类比较的强类型静态语言相比,在很多场景下方便很多(虽然性能跟屎一样的╮(╯_╰)╭)。这些便利也造就了Python庞大的生态,目前还没看到哪个语言的生态能像python这样子的(个人观点,欢迎抬杠)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_dwSun_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值