Dizenin listedeki dizelerden biriyle bitip bitmediğini kontrol edin


220

Aşağıdaki kodu yazmanın pythonic yolu nedir?

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

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

forDöngünün açık beyanının önlenebileceği ve ifkoşulda yazılabileceği belirsiz bir anım var . Bu doğru mu?


2
Bu soru iyi cevaplanmış olmasına rağmen, belki de yazar aslında düşündü if any((file_name.endswith(ext) for ext in extensions)).
sapht

Yanıtlar:


450

Yaygın olarak bilinmemekle birlikte, str.ends ile bir demet kabul eder. Dönmeye gerek yok.

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

10
neden bir listeyi kabul etmeyeceğini biliyor musunuz ama bir grup mu? sadece meraklı
ilyail3

2
@falsetru Yanıttaki bağlantı bu soruyu açıkça yanıtlamıyor. Sadece tupleleri kabul edebileceğinden söz ediyor , ancak listeleri neden kabul edemediğini değil . Her ikisi de sekans olduğundan, potansiyel olarak görebildiğim tek fark, listelerin değişebilirken, tupler değişmez olmasıdır. Yanılıyor olabilirim, ancak bunun açıkça ifade edilmesinin başka bir sebebini göremiyorum.
KymikoLoco

4
Bir dizenin bir harfle bitip bitmediğini kontrol etmek istiyorsanız:import string; str.endswith(tuple(string.ascii_lowercase))
Alex Willison

3
sadece bir not, endswithsadece python 2.5 ve üstü için tuple kabul ediyor
Akash Singh

1
Bunu hiç bilmiyordum! Mükemmel!
fool4jesus


6

Dosyadan bir uzantı alın ve uzantı kümesinde olup olmadığını görün:

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

Kümelerdeki aramalar için zaman karmaşıklığı bir küme kullanmak O (1) ( dokümanlar ) ' dır .


8
Verimlilikten bahsettiğiniz gibi, oldukça kısa tuples için .endswith(), bir stajyer tup ile ayarlanmış bir aramadan daha hızlı olacaktır
Jon Clements

@JonClements Ben cevaplar ve sorular harika notlar yapmak için özel bir SO altın yorum rozeti gerektiğini düşünüyorum :)
alecxe

Nah - Ben sadece "Alecxe Stalking" rozeti için gidiyorum;)
Jon Clements

2
2.7 ve daha yeni sürümlerde, kümeler için matematik sözdizimini bize yapabileceğinizi {'.mp3','.avi'}, ekstra tür dönüşümünü önlediğini ve arka planınıza bağlı olarak daha okunabilir olabileceğini unutmayın ('Sözlüklerle karışıklığa neden olabilir ve boş oluşturmak için kullanılamaz. setleri).
Perkins

@JonClements bir gün senin gibi bilge olacağım :)
alecxe

3

İki yol vardır: normal ifadeler ve string (str) yöntemleri.

Dize yöntemleri genellikle daha hızlıdır (~ 2x).

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)

Loop başına 792 ns ± 1.83 ns (7 çalışmanın ortalama ± standart sapması, her biri 1000000 döngü)

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

Çevrim başına 274 ns ± 4,22 ns (7 çalışmanın ortalama ± standart sapması, her biri 1000000 döngü)


1

Bu bende var:

def has_extension(filename, extension):

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

1
Yani return filename.endswith(ext)? : P
Mr_and_Mrs_D

1

Başka bir şey ararken, bununla karşılaştım.

osPaketteki yöntemlerle gitmenizi tavsiye ederim . Bunun nedeni, daha garip bir durumu telafi ederek daha genel hale getirebilmenizdir.

Gibi bir şey yapabilirsiniz:

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

Başka bir olasılık da IN deyimini kullanmak olabilir:

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

@ Rainald62, bu durumda indexolmalı rindex.
NeverHopeless

0

eşleşen dizelerin listesini döndüren başka bir yol

sample = "alexis has the control"
matched_strings = filter(sample.endswith, ["trol", "ol", "troll"])
print matched_strings
['trol', 'ol']
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.