2

你好。我想知道是否有一种方法可以递归地将项目添加到列表中。该函数应该打印与 fname 匹配的文件的路径名。所以 fname 是文件名,path 是文件所在的文件夹。如果路径文件夹中有文件夹,它将进入并查找 fname 文件。到目前为止,我能够找到所有文件。但我无法递归地附加列表。

def findAll(fname, path): 
 lst= []
 for item in os.listdir(path):
        n = os.path.join(path, item)
    try:
        if item == fname:
            lst.append(n)
    except:
        findAll(fname,n)
return lst
4

5 回答 5

4

Normally, I wouldn't give a full solution because this smells like homework (which is also why I'm avoiding os.walk), but since you have posted your attempt, here's an explanation and a solution:

For one thing, every time you call findAll, you initialize lst. Sure, you return it at the end, but you don't do anything with the return value, so the effect lst.append is contained within the recursion and is therefore not visible outside. Let me try to draw diagram to explain this (with one level of recursion):

+--------------------------------------------------+
|Outer Level:                                      |
|                                                  |
|`lst = []`                                        |
|found file f1 with name fname                     |
|`lst.append(f1)`                                  |
|+------------------------------------------------+|
||Inner Level                                     ||
||                                                ||
||`lst=[]`                                        ||
||found file f2 with name fname                   ||
||`lst.append(f2)`                                ||
||`return lst`                                    ||
|+------------------------------------------------+|
|a list is returned from recursive call,           |
|but not assigned to a variable.                   |
|Therefore, `lst` remains unchanged                |
+--------------------------------------------------+

There are a couple of ways by which you can fix this:

  1. move lst to a scope outside findAll (personally, this is what I would do)
  2. use the return value from the recursive call to modify lst

move lst to a scope outside findAll

lst= []
def findAll(fname, path): 
    global lst
    for item in os.listdir(path):
        n = os.path.join(path, item)
        try: # really though, you don't need to use try/except here
            if item == fname:
                lst.append(n)
            else:
                findAll(fname,n)
        except:
            pass

After findAll has terminated, lst will contain the values you want

use the return value from the recursive call to modify lst

def findAll(fname, path, answer=None):
    if answer == None:
        answer = []
    for item in os.listdir(path):
        n = os.path.join(path, item)
        try:
            if item == fname:
                answer += [n]
        except:
            findAll(fname,n, answer)
    return answer

Hope this helps

PS: of course, the non-homework way to do this would be to use os.walk:

answer = []
def findAll(fname, dirpath):
    dirpath, dirnames, filenames = os.walk(dirpath)
    for filename in filenames:
        if filename == fname:
            answer.append(os.path.join(dirpath, filename))
    for dirname in dirnames:
        findAll(fname, os.path.join(dirpath, dirname))
# now, answer contains all the required filepaths

EDIT: OP asked for a version that doesn't use global variables:

def findAll(fname, root, answer=None):
    if answer == None:
        answer = []
     for entry in os.listdir(root):
         if os.path.isdir(os.path.join(root, entry)):
             answer += findAll(fname, os.path.join(root, entry))
         else:
             if entry == fname:
                 answer.append(os.path.join(root, entry))
     return answer
于 2012-11-03T04:46:52.777 回答
1

你需要用你的递归调用来扩展你的列表

list.extend(findAll(fname,n))

你也可以检查某些东西是否是一个目录os.path.isdir(n)

但我认为你的脚本有更多的问题

afaiklistdir只返回名称,而不是目录的路径....

所以你需要打电话 findAll(fname,os.path.join(path,n))

于 2012-11-03T04:19:42.330 回答
0

如果您使用的是基于 Unix 的系统,则可以使用findsubprocess模块 .. 我认为这将是检索与文件名匹配的所有路径的最快方法。然后,您可以split()对输出执行 a 以使其成为列表:

>>> import subprocess
>>> lst = subprocess.check_output('find . -name "*rst"', shell=True)
>>> print lst
    ./SphinxWorkspace/doc/chapter1.rst
    ./SphinxWorkspace/doc/index.rst
    ./SphinxWorkspace/doc/tables.rst

您始终可以拆分命令并避免shell=True

结帐:http ://docs.python.org/2/library/subprocess.html#using-the-subprocess-module ..希望这会有所帮助!

于 2012-11-03T05:56:41.767 回答
0

Not related to the question per se but I believe that os.walk would help you out:

allFiles = []
for root, dirs, files in os.walk(basedir):
    [allFiles.append(file) for file in files]

Check out help(os.walk), it comes with a great example on how to use this function.

于 2012-11-03T04:47:00.770 回答
0

try/except在您的代码中使用不正确。except子句仅在出现错误时执行。此外,您不使用来自findAll(). 您可以跳过在函数内创建列表,而只是懒惰地产生找到的项目:

import os

def findAll(filename, rootdir): 
    for item in os.listdir(rootdir):
        path = os.path.join(rootdir, item)
        if not os.path.isdir(path):
            if item == filename: # don't select dirs
                yield path
        else: # path is a dir
            try:
                for found_path in findAll(filename, path):
                    yield found_path
            except EnvironmentError:
                pass # ignore errors

print(list(findAll('python', '/usr')))

输出

['/usr/bin/python']

如果这不是家庭作业,您可以使用它os.walk()来查找文件:

import os

def find_all(filename, rootdir):
    for dirpath, dirs, files in os.walk(rootdir):
        for file in files:
            if file == filename:
                yield os.path.join(dirpath, file)


print(list(find_all('python', '/usr')))

输出

['/usr/bin/python']

它与预期的输出相同。

于 2012-11-03T04:48:04.880 回答