Несколько не вложенных условий if в понимании списка без терминала else

#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