Очистка вложенных циклов в python

1

У меня есть этот код:

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 their own damn fault when it shows on the list.)
    return templist #Return a (not so) properly filtered list of steam logins.

Моя проблема в том, что она выглядит ужасно уродливой для меня. Я составил список из двух путей (только один из них будет когда-либо существовать), перейдя по этим путям, затем мне нужно получить список элементов в этих путях, а затем пройти их и отфильтровать из него не каталоги, чтобы получить псевдо-список паровых логинов на компьютере пользователя. (В основном просто получить список любых существующих каталогов (только каталогов!) По любому из этих двух путей)

Есть ли более короткий способ сделать это (кроме конденсации для петель в одиночные строки?)?

Мне бы очень хотелось дать англоязычное решение, чтобы я мог собрать его вместе; а не кода. Это единственный способ, которым я действительно научусь правильно. Даже приятный маленький намек или выдержка, чтобы я мог понять это сам по себе, было бы хорошо.

И: Всегда ли нужно перебирать списки для циклов, как:

for x in range(len(somelist)):

или есть что-то меньшее, чем использование диапазона (len (?

  • 1
    Почему вы не используете определения функций, чтобы упростить это?
  • 0
    Может быть, поэтому я и задал вопросы, потому что я новичок ...
Теги:

5 ответов

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
    Хотя при этом используется длинное понимание списка (два цикла и условие), обратите внимание, что при правильном отступе / разрыве строки он все еще читается. «Сжатие циклов в одну строку» не обязательно означает, что оно на одной строке, или плотное и безобразное!
  • 1
    Неважно, сколько строк вы ее разложите, тем не менее, она останется плотной, безобразной и нечитаемой.
Показать ещё 3 комментария
5

И: У списков для циклов всегда есть для прохождения:

для x в диапазоне (len (somelist)): или там что-то короче, чем использование диапазон (len (?

Конечно, есть, если вы хотите получить доступ к элементу, и вы не заинтересованы в его индексе, вы можете сделать это:

for x in somelist:

Если вам нужен индекс, вы можете сделать это:

for index, x in enumerate(somelist):
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):

При объединении for и if s, вы также должны взглянуть на выражения генераторов и списки (см. docs).

  • 0
    Благодарю. К сожалению, я работал с ... VB4 еще тогда, когда я был подростком, а затем внезапно прекратил программировать. Многие очень запутанные вещи остаются со мной, и я пытаюсь многое отучить, чтобы облегчить задачу.
  • 0
    @ThantiK: переполнение стека как раз для этого :-) И, что касается изучения Python, вы оцените многие вещи, которые Py.thon делает для облегчения своей жизни, чем VB4
Показать ещё 1 комментарий
2

Как уже упоминалось, удаление предположения о целых индексах устраняет большую сложность.

Идем дальше, вы можете заменить шаблоны, в которых вы создаете список, добавляя в цикле 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)) ]
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 может быть удален из функции, потому что это не является существенным для логики кода.

изменить: обновлено, чтобы возвращать поддиры первого существующего каталога в соответствии с вопросом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню