Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 递归函数的屈服_Python_Recursion_Iterator_Directory Structure_Yield - Fatal编程技术网

Python 递归函数的屈服

Python 递归函数的屈服,python,recursion,iterator,directory-structure,yield,Python,Recursion,Iterator,Directory Structure,Yield,我正在尝试对给定路径下的所有文件执行某些操作。我不想事先收集所有文件名,然后再对其进行处理,因此我尝试了以下方法: import os import stat def explore(p): s = '' list = os.listdir(p) for a in list: path = p + '/' + a stat_info = os.lstat(path ) if stat.S_ISDIR(stat_info.st_mode): expl

我正在尝试对给定路径下的所有文件执行某些操作。我不想事先收集所有文件名,然后再对其进行处理,因此我尝试了以下方法:

import os
import stat

def explore(p):
  s = ''
  list = os.listdir(p)
  for a in list:
    path = p + '/' + a
    stat_info = os.lstat(path )
    if stat.S_ISDIR(stat_info.st_mode):
     explore(path)
    else:
      yield path

if __name__ == "__main__":
  for x in explore('.'):
    print '-->', x
但这段代码在命中目录时跳过目录,而不是生成目录内容。我做错了什么?

使用而不是重新发明轮子

特别是,以下是库文档中的示例,这是一个未经测试的尝试:

import os
from os.path import join

def hellothere(somepath):
    for root, dirs, files in os.walk(somepath):
        for curfile in files:
            yield join(root, curfile)


# call and get full list of results:
allfiles = [ x for x in hellothere("...") ]

# iterate over results lazily:
for x in hellothere("..."):
    print x
试试这个:

if stat.S_ISDIR(stat_info.st_mode):
    for p in explore(path):
        yield p

像函数一样调用
explore
。您应该做的是像生成器一样迭代它:

if stat.S_ISDIR(stat_info.st_mode):
  for p in explore(path):
    yield p
else:
  yield path

编辑:您可以使用
os.path.isdir(path)
迭代器不会像那样递归工作,而不是
stat
模块。您必须通过替换来重新生成每个结果

explore(路径)
有点像

explore(路径)中的值的
:
收益率
按照中的建议,添加了X的语法
yield from X
,以达到此目的。使用它,您可以执行以下操作:

explore的收益(路径)
如果使用,此语法还支持使用将值传递回递归调用的生成器。上面的循环的简单

将不会改变这一点:

explore(path)
为此:

for subpath in explore(path):
    yield subpath

或者使用phooji建议的
os.walk

问题在于这行代码:

explore(path)
它有什么作用

  • 使用新的
    路径调用
    explore
  • 探索
    运行,创建生成器
  • 生成器返回到执行
    explore(path)
    的位置
  • 并且被丢弃
为什么要丢弃它?它没有被分配给任何东西,也没有被迭代——它被完全忽略了

如果你想对结果做点什么,那么,你必须对结果做点什么!;)

修复代码的最简单方法是:

for name in explore(path):
    yield name
当您确信自己了解了正在发生的事情时,您可能希望使用
os.walk()

一旦迁移到Python 3.3(假设所有工作都按计划进行),您将能够使用新的
yield from
语法,此时修复代码的最简单方法是:

yield from explore(path)

如果您需要遍历所有文件夹和子文件夹,那么os.walk非常好。如果你不需要的话,那就像用象枪杀苍蝇一样


但是,对于这种特定情况,os.walk可能是一种更好的方法。

您也可以使用堆栈实现递归

然而,这样做并没有任何好处,除了这是可能的。如果您首先使用python,那么性能的提高可能是不值得的

import os
import stat

def explore(p):
    '''
    perform a depth first search and yield the path elements in dfs order
        -implement the recursion using a stack because a python can't yield within a nested function call
    '''
    list_t=type(list())
    st=[[p,0]]
    while len(st)>0:
        x=st[-1][0]
        print x
        i=st[-1][1]

        if type(x)==list_t:
            if i>=len(x):
                st.pop(-1)
            else:
                st[-1][1]+=1
                st.append([x[i],0])
        else:
            st.pop(-1)
            stat_info = os.lstat(x)
            if stat.S_ISDIR(stat_info.st_mode):
                st.append([['%s/%s'%(x,a) for a in os.listdir(x)],0])
            else:
                yield x

print list(explore('.'))

要回答最初的问题,关键是
yield
语句需要从递归中传播回来(就像
return
)。下面是对
os.walk()
的重新实现。我在一个伪VFS实现中使用了它,在这里我另外替换了
os.listdir()
和类似的调用

import os, os.path
def walk (top, topdown=False):
    items = ([], [])
    for name in os.listdir(top):
        isdir = os.path.isdir(os.path.join(top, name))
        items[isdir].append(name)
    result = (top, items[True], items[False])
    if topdown:
        yield result
    for folder in items[True]:
        for item in walk(os.path.join(top, folder), topdown=topdown):
            yield item
    if not topdown:
        yield result

这应该是IMHO接受的答案,因为问题是关于产量和递归,而不是关于实现os.walk的最佳方式;-)!!!我在这个非常简单的循环中打破了我的头。。。事实上,所有其他答案都在同一条线上…谢谢你!提到3.3和迭代器是非常有用的。正如在PyCon2014的演讲中提到的,生成器可以用来绕过递归限制!给出工作代码是好的,但解释OP做错了什么,特别是当他们要求这样做时,就更好了。问题是关于产量和递归,而不是实现os的最佳方式。walk也:在Python 2中,walk比listdir慢,请看一些语言可以产生整个序列,而不仅仅是单个元素。我不认为Python是其中之一。由于标题提出了一个比OS.WORK解决的更普遍的问题,请考虑如下:DEF探索(p):如果是实例(p,(list,tuple)):对于p中的x:探索(p),否则:屈服p,这有同样的问题。为什么不起作用?