当前位置: 首页 > 知识库问答 >
问题:

自己写的os.walk比自己os.walk慢得多-为什么?

尤夕
2023-03-14

不幸的是,这段代码运行速度比“os.walk”慢,但为什么呢?

会不会是“为”循环导致它运行缓慢?

类似于“os.walk”的代码:(“os.walk”函数完成它的功能)

注意:我写信是为了提高自己!:

import os, time
from os.path import *

x = ""
y = []
z = []
var = 0

def walk(xew):
    global top, var, x,y,z
    if not var: var = [xew]
    for i in var:
        try:
            for ii in os.listdir(i):
                y.append(ii) if isdir(i+os.sep+ii) else z.append(ii)

            x = top = i
            var = [top+os.sep+i for i in os.listdir(top) if isdir(top+os.sep+i)]         
        except:
            continue
        yield x,y,z
        yield from walk(var)
        var.clear();y.clear();z.clear()

例如:

2秒内结束:

for x,y,z in walk(path):
    print(x)

在0.5秒内:

for x,y,z in os.walk(path):
    print(x)

共有2个答案

楮杰
2023-03-14

这段代码的运行速度几乎与os一样快。步行

import os, time
from os.path import *

def walk(top):
    x = top;y=[];z=[]
    try:
        for i in os.listdir(top):
            y.append(i) if isdir(top+os.sep+i) else z.append(i)
    except: pass
    else:
        yield x,y,z
        for q in y: yield from walk(top+os.sep+q)
麹渊
2023-03-14

os。walk()不使用操作系统。listdir()。它使用更快的操作系统。scandir()函数,该函数为迭代器提供每个目录项的更多信息:

使用scandir()代替listdir()可以显著提高还需要文件类型或文件属性信息的代码的性能,因为os.如果操作系统在扫描目录时提供此信息,则DirEntry对象会公开此信息。所有os.DirEntry方法可以执行系统调用,但是is_dir()is_file()通常只需要符号链接的系统调用;os。DirEntry.stat()在Unix上总是需要一个系统调用,但在Windows上只需要一个符号链接。

os。walk()code大量使用DirEntry。is_dir()call,它与os一起使用。scandir()比使用操作系统便宜得多。isdir()(必须进行单独的os.stat()调用)。

接下来,您的代码经常调用os.isdir()。您实际上对路径中的每个文件条目调用它两次。您已经收集了y中的所有子目录,当重新创建var时,您不需要再次测试路径。这些额外的isdir()调用花费了您大量的时间。

var为空(没有其他子目录)时,您也会递归,这会导致您首先将空列表包装到另一个列表中,然后是os。listdir()抛出一个类型错误异常,你的毛毯口袋妖怪会捕捉到除处理程序沉默之外的所有异常。

接下来,您应该去掉全局变量,并使用适当的变量名<代码>文件和目录的名称要比yz清晰得多。因为您创建了yz全局文件,所以您将保留给定级别的所有文件和目录名,并且对于向下的每个第一个子目录,您将重新报告这些相同的文件和目录名,就好像它们是这些子目录的成员一样。只有当到达这样一个目录树的第一个叶子(没有更多的子目录)时,。clear()执行对yz的调用,导致重复文件名的结果非常混乱。

您可以研究操作系统。walk()源代码,但如果我们将其简化为只使用自顶向下遍历而不使用错误处理,那么它将归结为:

def walk(top):
    dirs = []
    nondirs = []

    with os.scandir(top) as scandir_it:
        for entry in scandir_it:
            if entry.is_dir():
                dirs.append(entry.name)
            else:
                nondirs.append(entry.name)

    yield top, dirs, nondirs

    for dirname in dirs:
        new_path = os.path.join(top, dirname) 
        yield from walk(new_path)

注意,没有使用全局变量;在这个算法中根本不需要任何额外的参数。只有一个操作系统。scandir()调用每个目录,并重复使用dirs变量递归到子目录中。

 类似资料:
  • 问题内容: 我有一段旧代码,用于在字符串中执行查找和替换标记。 它接收地图的和对,遍历它们并为每个对,遍历目标字符串,将查找使用,并取代它的价值。它完成对的所有工作,并最终返回。 我用以下代码替换了该代码: 并且运行了一些比较性能测试。 比较迭代时,我得到以下信息: 旧代码:1287ms 新代码:4605ms 长3倍! 然后,我尝试用3个调用替换它: 结果如下: 旧代码:1295 新代码:3524

  • 目标 写出一个loader,实现在html文件内容前面添加个人签名、以及自动替换掉敏感词汇的功能,当对应的词汇文件修改时,页面会自动刷新。该loader需能够协作其他loader,实现链式调用。 挑战 写出一个loader,要求每个模块文件依赖于各不相同的敏感词汇json文件。 知识点 1、node module:一个loader就是一个npm包,输出一个function; 2、npm publi

  • 对于简单的定制操作,我们或许可以通过使用layers.core.Lambda层来完成。但对于任何具有可训练权重的定制层,你应该自己来实现。 这里是一个Keras层应该具有的框架结构(1.1.3以后的版本,如果你的版本更旧请升级),要定制自己的层,你需要实现下面三个方法 build(input_shape):这是定义权重的方法,可训练的权应该在这里被加入列表`self.trainable_weigh

  • 对于简单的定制操作,我们或许可以通过使用layers.core.Lambda层来完成。但对于任何具有可训练权重的定制层,你应该自己来实现。 这里是一个Keras2的层应该具有的框架结构(如果你的版本更旧请升级),要定制自己的层,你需要实现下面三个方法 build(input_shape):这是定义权重的方法,可训练的权应该在这里被加入列表`self.trainable_weights中。其他的属性

  • 对于简单、无状态的自定义操作,你也许可以通过 layers.core.Lambda 层来实现。但是对于那些包含了可训练权重的自定义层,你应该自己实现这种层。 这是一个 Keras 2.0 中,Keras 层的骨架(如果你用的是旧的版本,请更新到新版)。你只需要实现三个方法即可: build(input_shape): 这是你定义权重的地方。这个方法必须设 self.built = True,可以通

  • 前面已经提过在运行 logstash 的时候,可以通过 --pluginpath 参数来加载自己写的插件。那么,插件又该怎么写呢? 插件格式 一个标准的 logstash 输入插件格式如下: require 'logstash/namespace' require 'logstash/inputs/base' class LogStash::Inputs::MyPlugin < LogStash: