2

やあ。リストにアイテムを再帰的に追加する方法があるかどうか疑問に思っていました。この関数は、fname に一致するファイルのパス名を出力することになっています。したがって、fname はファイルの名前で、パスはファイルが置かれているフォルダーです。パス フォルダー内にフォルダーがある場合は、その中に移動して 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

通常、これは宿題のようなにおいがするため、完全な解決策を提供しません (これが私が回避している理由でもありos.walkます) が、あなたが試みを投稿したので、ここに説明と解決策があります:

まず、 を呼び出すたびfindAllに を初期化しますlst。確かに、最後にそれを返しますが、戻り値には何もしないので、効果lst.appendは再帰内に含まれているため、外部には表示されません。これを説明する図を描いてみましょう (1 レベルの再帰を使用)。

+--------------------------------------------------+
|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                |
+--------------------------------------------------+

これを修正するには、いくつかの方法があります。

  1. lst外部のスコープに移動しますfindAll(個人的には、これが私がすることです)
  2. 再帰呼び出しからの戻り値を使用して変更しますlst

lst外部のスコープに移動する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

findAllが終了した後lst、必要な値が含まれます

再帰呼び出しからの戻り値を使用して変更します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

お役に立てれば

PS:もちろん、これを行うための宿題以外の方法は、次を使用すること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

編集:OPは、グローバル変数を使用しないバージョンを要求しました:

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

質問自体には関係ありませんが、それがos.walkあなたの助けになると思います:

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

をチェックしてくださいhelp(os.walk)。この関数の使用方法に関する優れた例が付属しています。

于 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 に答える