在python中清理嵌套for循环

时间:2010-01-21 16:12:24

标签: python

我有这段代码:

def GetSteamAccts(): #Get list of steam logins on this computer.
    templist = []
    Steamapp_Folders = ["C:\\Program Files (x86)\\Steam\\steamapps\\", "C:\\Program Files\\Steam\\steamapps\\"] #Check both of these directories.
    for SF_i in range(len(Steamapp_Folders)):
        if os.path.exists(Steamapp_Folders[SF_i]): #If the directory even exists...
            Steam_AppDir_Items = os.listdir(Steamapp_Folders[SF_i]) #List items under steam install directory.
            for S_AD_i in range(len(Steam_AppDir_Items)): #Make sure the user doesn't have any files in here...
                if os.path.isdir(Steamapp_Folders + Steam_AppDir_Items[S_AD_i]): #If our path is a directory...
                    templist.append(Steam_AppDir_Items[S_AD_i])  #Add it to our list of logins.
                                                                 #(If some idiot puts extra folders in here,
                                                                 #it's their own damn fault when it shows on the list.)
    return templist #Return a (not so) properly filtered list of steam logins.

我的问题是,它对我来说看起来很难看。我列出了2个路径(只有1个将存在),循环遍历这些路径,然后我必须获取这些路径中的项目列表,然后遍历这些路径并从中过滤掉非目录以获取用户计算机上的蒸汽登录的伪列表。 (基本上只是获取这两个路径之一的任何现有目录(仅限目录!)的列表)

是否有更短的方法(除了将循环压缩成单行?)?

我宁愿给出一个英语措辞的解决方案,所以我可以把它放在一起;而不是代码。这是我真正学会正确方法的唯一方法。即使是一个很好的小提示或摘录,所以我可以自己解决它会很好。

并且:for循环中的列表总是必须遍历:

for x in range(len(somelist)):

还是比使用范围更短(len(?

5 个答案:

答案 0 :(得分:9)

for i in range(len(somelist)):
   something( somelist[i] )

应该写成

for x in somelist: 
    something( x )

你也可以把所有东西写得更短:

def GetSteamAccts():
    Steamapp_Folders = [f for f in ("C:\\Program Files (x86)\\Steam\\steamapps\\", 
                                    "C:\\Program Files\\Steam\\steamapps\\") 
                          if os.path.isdir(f)]
    return [os.path.join(root, folder) 
                    for root in Steamapp_Folders 
                    for folder in os.listdir(root) 
                    if os.path.isdir( os.path.join(root, folder)) ]

这看起来更干净,实际上做了你想要的:; - )

def subfoldernames( root ):
    for folder in os.listdir(root):
        path = os.path.join(root, folder)
        if os.path.isdir(path):
            yield folder # just the name, not the path

# same, just shorter:
def subfoldernames( root ):
    # this returns a generator, written as a generator expression
    return ( folder for folder in os.listdir( root ) 
                    if os.path.isdir(os.path.join( root, folder )) )

def GetSteamAccts():
        Steamapp_Folders = ("C:\\Program Files (x86)\\Steam\\steamapps\\", 
                                             "C:\\Program Files\\Steam\\steamapps\\")
        for folder in Steamapp_Folders:
            if os.path.isdir(folder):
                # only the subfolders of the first path that exists are returned
                return list(subfoldernames( folder )) 

答案 1 :(得分:5)

  

并且:for循环中的列表总是有   像遍历一样遍历:

     

对于范围内的x(len(somelist)):或者是   比使用更短的东西   范围(len(?

当然,如果您只想访问该项目并且您对其索引不感兴趣,您可以这样做:

for x in somelist:

如果你想要索引,你也可以这样做:

for index, x in enumerate(somelist):

答案 2 :(得分:4)

你应该忘记for循环总是迭代数字从零到某些东西,就像在其他语言中一样。你只是遍历列表,所以使用这样的for循环:

def GetSteamAccts():
    templist = []
    Steamapp_Folders = ["C:\\Program Files (x86)\\Steam\\steamapps\\", "C:\\Program Files\\Steam\\steamapps\\"] #Check both of these directories.
    for steamapp_folder in Steamapp_Folders:
        if os.path.exists(steamapp_folder):
            for steam_appDir_item in os.listdir(steamapp_folder):
                if os.path.isdir(os.path.join(steamapp_folder, steam_appDir_item)):
                    templist.append(steam_appDir_item)
    return templist

在Python中,for循环遍历任何可以迭代的东西。对于那些你真正需要数字(而且只有数字)的次数,有range。对于那些需要数字和项目的时间,请使用:

for number, item in enumerate(my_list):

在合并forif时,您还应该查看生成器表达式和列表推导(请参阅docs)。

答案 3 :(得分:2)

正如其他人所提到的,删除关于整数索引的假设会消除大量的复杂性。

更进一步,您可以通过在list comprehension的for循环中附加来替换构建列表的模式。一旦进入几层嵌套,这些提高可读性的程度(或是否)是值得商榷的,但它们确实使代码更加简洁:

def GetSteamAccts():
    Steamapp_Folders = ["C:\\Program Files (x86)\\Steam\\steamapps\\", "C:\\Program Files\\Steam\\steamapps\\"] #Check both of these  directories.
    return [ item for folder in Steamapp_Folders if os.path.exists(folder)
                  for item in os.listdir(folder) if os.path.isdir(os.path.join(folder, item)) ]

答案 4 :(得分:0)

我建议这样的事情:

def check_subfolder(*args):
    for folder in args:
         for root, dirs, _ in os.walk(folder):
              return [os.path.join(root, i) for i in dirs]  # since only 1 will ever exist

它只是保存所有if语句。当然,第一个for循环可以移出函数,因为它对代码的逻辑不是必不可少的。

编辑:更新为根据问题返回第一个现有目录的子目录。