Перевірте, чи рядок закінчується одним із рядків зі списку


220

Який пітонічний спосіб написання наступного коду?

extensions = ['.mp3','.avi']
file_name = 'test.mp3'

for extension in extensions:
    if file_name.endswith(extension):
        #do stuff

У мене неясна пам'ять, що явного оголошення forциклу можна уникнути і записати в ifумові. Це правда?


2
Хоча на це питання добре відповіли, можливо, автор спочатку подумав if any((file_name.endswith(ext) for ext in extensions)).
sapht

Відповіді:


450

Хоча широко відома, str.endswith також приймає кортеж. Вам не потрібно циклічно.

>>> 'test.mp3'.endswith(('.mp3', '.avi'))
True

10
ти знаєш, чому він не приймає список, але робить кортеж? просто цікаво
ilyail3

2
@falsetru Посилання у відповіді прямо не відповідає на це запитання. Він лише згадує, що може приймати кортежі, але не тому, що не може приймати списки. Оскільки вони є обома послідовностями, єдина різниця, яку я потенційно бачу, полягає в тому, що списки є змінними, а кортежі - незмінні. Я можу помилятися, але я не бачу жодної іншої причини, чому це прямо сказано.
KymikoLoco

4
Якщо ви хочете перевірити, чи закінчується рядок буквою:import string; str.endswith(tuple(string.ascii_lowercase))
Алекс Віллісон

3
лише примітка, endswithприймає кортеж лише для python 2.5 і вище
Акаш Сінгх

1
Ніколи цього не знав! Це ідеально!
crazy4jesus


6

Візьміть розширення з файлу і подивіться, чи є він у наборі розширень:

>>> import os
>>> extensions = set(['.mp3','.avi'])
>>> file_name = 'test.mp3'
>>> extension = os.path.splitext(file_name)[1]
>>> extension in extensions
True

Використання набору, тому що складність часу для пошуку в множинах становить O (1) ( документи ).


8
Зауважимо, коли ви згадуєте про ефективність, для досить коротких кортежів, .endswith()інтернований кортеж буде швидшим, ніж пошук набору
Jon Clements

@JonClements Я думаю, вам потрібен спеціальний знак золотого коментаря SO для створення дивовижних записок щодо відповідей та запитань :)
alecxe

Нет - я просто збираюся значком "Сталкінга alecxe";)
Джон Клементс

2
Зауважте також, що в 2.7 і новіших версіях ви можете використовувати синтаксис математики для наборів, {'.mp3','.avi'}це дозволяє уникнути перетворення додаткового типу і може бути більш читабельним залежно від вашого фону ("Хоча це може спричинити плутанину зі словниками, і не може бути використане для створення порожніх") набори).
Перкінс

@JonClements якось я стану таким же мудрим, як і ти :)
alecxe

3

Є два способи: регулярні вирази та рядкові (str) методи.

Методи рядків зазвичай швидші (~ 2х).

import re, timeit
p = re.compile('.*(.mp3|.avi)$', re.IGNORECASE)
file_name = 'test.mp3'
print(bool(t.match(file_name))
%timeit bool(t.match(file_name)

792 нс ± 1,83 нс на цикл (середнє ± ст. Розм. 7 пробігів, 1000000 циклів у кожній)

file_name = 'test.mp3'
extensions = ('.mp3','.avi')
print(file_name.lower().endswith(extensions))
%timeit file_name.lower().endswith(extensions)

274 нс ± 4,22 нс на цикл (середнє ± ст. Розв. 7 пробігів, 1000000 циклів кожна)


1

У мене це:

def has_extension(filename, extension):

    ext = "." + extension
    if filename.endswith(ext):
        return True
    else:
        return False

1
Ви маєте на увазі return filename.endswith(ext)? : P
Mr_and_Mrs_D

1

Я просто натрапив на це, шукаючи щось інше.

Я б рекомендував перейти з методами в osпакеті. Це тому, що ви можете зробити це більш загальним, компенсуючи будь-який дивний випадок.

Ви можете зробити щось на кшталт:

import os

the_file = 'aaaa/bbbb/ccc.ddd'

extensions_list = ['ddd', 'eee', 'fff']

if os.path.splitext(the_file)[-1] in extensions_list:
    # Do your thing.

0

Іншою можливістю може бути використання оператора IN:

extensions = ['.mp3','.avi']
file_name  = 'test.mp3'
if "." in file_name and file_name[file_name.rindex("."):] in extensions:
    print(True)

@ Rainald62, indexмає бути rindexв такому випадку.
NeverHopeless

0

ще один спосіб повернення списку відповідних рядків

sample = "alexis has the control"
matched_strings = filter(sample.endswith, ["trol", "ol", "troll"])
print matched_strings
['trol', 'ol']
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.