我正在构建一个Python脚本,以从任意子目录集中选择和打开文件。为此,我正在构建一个带有for循环的函数,以列出目录中所有文件的列表,以及该目录中所有子目录的另一个列表。然后,另一个for循环通过递归调用相同的函数来更改每个子目录。我在调试模式下反复执行了此功能,并仔细观察了每个变量的逐步更改。
我很困惑,因为每个循环都起作用了一点,但是随后退出而没有完成。通常,在编程中,功能完全或根本不起作用,但很少能半途而废。这两个循环都执行此操作,并且当第二次调用该函数退出时,它不会返回到第一次调用来完成其第二个循环,而是完全退出对该函数的所有调用。这是代码,非常感谢您的帮助:
def descend(directory, depth, dive=-1): # dive=-1 before we have touched the surface
global choices # list of files to be chosen from later
os.chdir(directory) # change to target directory
dirlist = [] # empty the list of directories within the directory
baseList = os.listdir(directory) # list of all files and directories
if dive < depth: # depth corresponds to the levels of sub-directories to be searched
dive += 1 # effectively starts at 0
fileIndex=0 # index as we step through the baseList
for x in baseList: # why doesn't this loop complete?
if os.path.isfile(x) == True: # if it's a regular file
path = directory + '/' + baseList.pop(fileIndex) # create its full path
choices.append(path) # and add that to our list of choices
elif os.path.isdir(x) == True: # if it's a directory
dirlist.append(baseList.pop(fileIndex)) # add to list of directories to recursively search
fileIndex += 1 # add 1 to the file index
for x in dirlist: # for each item in the list of directories
nextdir = directory + '/' + dirlist.pop() # make a variable of its full path
descend(nextdir, depth, dive) # pass that back to this function and repeat
我什至尝试了一些愚蠢的解决方案,例如将if len(baseList) != 0: continue
添加到循环的底部,这不需要重复两次,但这对任何一个都没有帮助。我完全迷住了。
答案 0 :(得分:0)
好的,我要在这里回答我自己的问题,因为我很好奇并且做了更多的研究,而且评论太久了。也许这将有助于澄清其他人。在弄清楚与IDLE一起玩的过程后,我在Pydoc中发现了这一点:
注意:当序列被 循环(这仅适用于可变序列,例如列表)。一个 内部计数器用于跟踪接下来要使用的项目, 并在每次迭代时增加。当这个柜台有 达到循环终止的序列长度。这表示 如果套件从中删除了当前(或上一个)项目 序列,下一个项目将被跳过(因为它获得了 当前已处理的项目)。同样,如果 套件按顺序在当前项目之前插入一个项目, 当前项目将在下一次循环中再次处理。 这可能会导致令人讨厌的错误,可以通过制作一个 使用整个序列的一部分进行临时复制,例如
for x in a[:]:
if x < 0: a.remove(x)
我的IDLE实验的输入和输出:
>>> baselist=[0,1,2,3,4,5,6,7,8,9]
>>> listeven=[]
>>> listodd=[]
>>> index=0
>>> for x in baselist:
print('baselist is ', baselist)
print('listeven is ', listeven)
print('listodd is ', listodd)
print('x is ', x)
print('index is ', index)
if x % 2 == 0:
print('appending ', x, ' to listeven by popping from baselist')
listeven.append(baselist.pop(index))
else:
print('appending ', x, ' to listodd by popping from baselist')
listodd.append(baselist.pop(index))
index += 1
baselist is [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
listeven is []
listodd is []
x is 0
index is 0
appending 0 to listeven by popping from baselist
baselist is [1, 2, 3, 4, 5, 6, 7, 8, 9]
listeven is [0]
listodd is []
x is 2
index is 1
appending 2 to listeven by popping from baselist
baselist is [1, 3, 4, 5, 6, 7, 8, 9]
listeven is [0, 2]
listodd is []
x is 4
index is 2
appending 4 to listeven by popping from baselist
baselist is [1, 3, 5, 6, 7, 8, 9]
listeven is [0, 2, 4]
listodd is []
x is 6
index is 3
appending 6 to listeven by popping from baselist
baselist is [1, 3, 5, 7, 8, 9]
listeven is [0, 2, 4, 6]
listodd is []
x is 8
index is 4
appending 8 to listeven by popping from baselist
>>> baselist
[1, 3, 5, 7, 9]
在中间循环中从列表中删除项目会使解释器认为它早已完成迭代,因为其隐藏的内部索引告诉它下一个索引超出范围,这意味着跳过了某些值!
现在此功能如下:
def descend(directory, depth, dive=-1):
global files
os.chdir(directory)
subBranches = []
baseList = os.listdir(directory)
if dive < depth:
dive += 1
for x in baseList:
if os.path.isfile(x) == True:
path = directory + '/' + x
files.append(path)
elif os.path.isdir(x) == True:
subBranches.append(x)
for x in subBranches:
nextdir = directory + '/' + x
descend(nextdir, depth, dive)