Python解释器在迭代完成之前退出循环:

时间:2019-02-28 10:41:29

标签: python loops for-loop recursion

我正在构建一个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添加到循环的底部,这不需要重复两次,但这对任何一个都没有帮助。我完全迷住了。

1 个答案:

答案 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)