У меня есть этот код:
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 (?
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 ))
И: У списков для циклов всегда есть для прохождения:
для x в диапазоне (len (somelist)): или там что-то короче, чем использование диапазон (len (?
Конечно, есть, если вы хотите получить доступ к элементу, и вы не заинтересованы в его индексе, вы можете сделать это:
for x in somelist:
Если вам нужен индекс, вы можете сделать это:
for index, x in enumerate(somelist):
Вы должны потерять представление о том, что цикл 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).
Как уже упоминалось, удаление предположения о целых индексах устраняет большую сложность.
Идем дальше, вы можете заменить шаблоны, в которых вы создаете список, добавляя в цикле 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)) ]
Я бы предложил что-то вроде этого:
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
может быть удален из функции, потому что это не является существенным для логики кода.
изменить: обновлено, чтобы возвращать поддиры первого существующего каталога в соответствии с вопросом.