您好。我想知道是否有办法递归地将项目添加到列表中。该函数应该打印与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
答案 0 :(得分:4)
通常情况下,我不会提供完整的解决方案,因为这有点像家庭作业(这也是我为什么要避免os.walk
),但既然你已经发布了你的尝试,这里有一个解释和解决方案:< / p>
首先,每次拨打findAll
时,都会初始化lst
。当然,你最后会返回它,但是你没有对返回值做任何事情,因此效果lst.append
包含在递归中,因此在外部不可见。让我试着用图解释一下(用一级递归):
+--------------------------------------------------+
|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 |
+--------------------------------------------------+
有几种方法可以解决这个问题:
lst
移至findAll
以外的范围(个人而言,这就是我要做的)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
答案 1 :(得分:1)
您需要使用递归调用扩展列表
list.extend(findAll(fname,n))
您也可以检查某些内容是否为os.path.isdir(n)
但我认为你的问题比你的脚本更多
afaik listdir
只返回名称,而不是目录的路径....
因此您需要致电findAll(fname,os.path.join(path,n))
答案 2 :(得分:0)
与本身问题无关,但我相信os.walk
可以帮助您:
allFiles = []
for root, dirs, files in os.walk(basedir):
[allFiles.append(file) for file in files]
查看help(os.walk)
,它提供了一个关于如何使用此功能的绝佳示例。
答案 3 :(得分: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']
它与预期的输出相同。
答案 4 :(得分:0)
如果您使用的是基于Unix的系统,则可以将find
与subprocess
模块一起使用..我认为这是检索与文件名匹配的所有路径的最快方法。然后,您可以在输出上执行split()
以使其成为列表:
>>> 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 希望这有帮助!