#python #list-comprehension
Вопрос:
(Примечание: прежде чем вы начнете искать дубликаты вопросов if-else, пожалуйста, ознакомьтесь с следующим разделом, чтобы узнать, почему многие из них не подошли мне)
Я хочу научиться использовать понимание списка, чтобы упростить два набора блоков кода в один:
filenameslist.extend(
[f[:-4] for f in filenames if (
f.endswith('.mp3') or
f.endswith('.wma') or
f.endswith('.aac') or
f.endswith('.ogg') or
f.endswith('.m4a')
)])
filenameslist.extend(
[f[:-5] for f in filenames if (
f.endswith('.opus')
)])
Я попытался достичь этого, используя следующий код после того, как последовал стольким ответам здесь, в SO. Однако для меня это не работает. Пожалуйста, взгляните на то, что у меня есть прямо сейчас:
filenameslist.extend(
[(f[:-4] if (
f.endswith('.mp3') or
f.endswith('.wma') or
f.endswith('.aac') or
f.endswith('.ogg') or
f.endswith('.m4a')
) else (f[:-5] if f.endswith('.opus') else '')) for f in filenames])
Ненужное else ''
в конце добавляет запись » в мой список, которая мне не нужна. Удаление else или использование else pass
приводит к синтаксической ошибке.
Я могу удалить ''
запись вручную из списка, но суть в том, чтобы научиться делать это на одном шаге с пониманием списка. Я использую py 3.8.
Ответ №1:
В выражении понимания вашего списка невозможно указать что-то вроде «не создавать элемент в этом случае» (когда расширение не входит в ваш список разрешенных расширений).
Вы должны каким-то образом повторить свой тест:
filenames = ['test.mp3', 'something.opus', 'dontcare.wav']
l = [
f[:-5] if f.endswith('.opus') else f[:-4]
for f in filenames
if (
f.endswith('.mp3') or
f.endswith('.wma') or
f.endswith('.aac') or
f.endswith('.ogg') or
f.endswith('.m4a') or
f.endswith('.opus')
)
]
print(l)
Обратите внимание, что вы можете использовать os.path.splitext
для облегчения своей работы:
import os
filenames = ['test.mp3', 'something.opus', 'dontcare.wav']
l = [
os.path.splitext(f)[0]
for f in filenames
if os.path.splitext(f)[1] in ['.mp3', '.wma', '.aac', '.ogg', '.m4a', '.opus']
]
print(l)
Комментарии:
1. Спасибо, что указали на исправление в моем существующем методе в дополнение к более простому подходу. Я выбрал его в качестве ответа из-за помощи в исправлении. Другие ответы здесь лучше, если вы просто ищете более простые альтернативы (это тоже без какого-либо дополнительного импорта библиотеки). Но мне действительно было полезно увидеть, что я пропустил в своем коде.
Ответ №2:
Используйте Path
встроенные свойства объектов вместо того, чтобы самостоятельно анализировать имена:
from pathlib import Path
filenames = Path('/some/folder/').glob('*')
allowed_suffixes = ['.mp3', '.wma', '.aac', '.ogg', '.m4a', '.opus']
file_stems = set(f.stem for f in filenames if f.suffix in allowed_suffixes)
Конечно, вы можете использовать список вместо набора. Это выглядит чище, чем сложное понимание списка. Если вы хотите сохранить полные пути к файлам, используйте:
file_stems = set(f.parent / f.stem for f in filenames if f.suffix in allowed_suffixes)
Ответ №3:
str.endswith
Метод может дополнительно принимать кортеж суффиксов, поэтому вы можете просто сделать:
allowed_suffixes = '.mp3', '.wma', '.aac', '.ogg', '.m4a', '.opus'
filenameslist.extend(f[:f.rfind('.')] for f in filenames if f.endswith(allowed_suffixes))
Комментарии:
1. Самая простая альтернатива, которая у меня есть до сих пор, без необходимости дополнительного импорта.
Ответ №4:
Вы можете использовать rpartition
, как показано ниже:
filenameslist.extend([fn.rpartition('.')[0] for fn in filenames if fn[fn.rfind('.'):] in suffixes])
Пример:
suffixes = ['.mp3', '.wma', '.aac', '.ogg', '.m4a', '.opus', '.wav']
filenames = ['test.mp3', 'something.opus', 'dontcare.wav', 'lara']
[fn.rpartition('.')[0] for fn in filenames if fn[fn.rfind('.'):] in suffixes]
Выход:
['test', 'something', 'dontcare']
Комментарии:
1. Я внес правку, которую нужно заменить
find('.')
наrfind('.')
. Если имя файла содержит.
before.extension
, функция rfind() все еще работает. Например: thisis.afile.name.txt