Dlaczego jest to string.join(list)
zamiast list.join(string)
?
Jest tak, ponieważ join
jest to metoda „ciągowa”! Tworzy ciąg z dowolnego iterowalnego. Jeśli utknęliśmy metodę na listach, co powiesz na to, kiedy mamy iteracje, które nie są listami?
Co jeśli masz krotkę sznurków? Gdyby to była list
metoda, musiałbyś rzucić każdy taki iterator ciągów, list
zanim mógłbyś połączyć elementy w jeden ciąg! Na przykład:
some_strings = ('foo', 'bar', 'baz')
Rzućmy własną metodą łączenia listy:
class OurList(list):
def join(self, s):
return s.join(self)
I aby go użyć, należy pamiętać, że musimy najpierw utworzyć listę z każdej iterowalnej, aby dołączyć do niej ciągi znaków, marnując zarówno pamięć, jak i moc przetwarzania:
>>> l = OurList(some_strings) # step 1, create our list
>>> l.join(', ') # step 2, use our list join method!
'foo, bar, baz'
Widzimy więc, że musimy dodać dodatkowy krok, aby użyć naszej metody list, zamiast po prostu wbudowanej metody ciągu:
>>> ' | '.join(some_strings) # a single step!
'foo | bar | baz'
Ograniczenie wydajności dla generatorów
Algorytm, którego używa Python, aby utworzyć końcowy ciąg, str.join
faktycznie musi dwukrotnie przejść przez iterowalny ciąg , więc jeśli podasz mu wyrażenie generujące, musi najpierw zmaterializować go na liście, zanim będzie mógł utworzyć końcowy ciąg.
Tak więc, chociaż przekazywanie generatorów jest zwykle lepsze niż rozumienie list, str.join
jest wyjątkiem:
>>> import timeit
>>> min(timeit.repeat(lambda: ''.join(str(i) for i in range(10) if i)))
3.839168446022086
>>> min(timeit.repeat(lambda: ''.join([str(i) for i in range(10) if i])))
3.339879313018173
Niemniej jednak str.join
operacja jest nadal semantycznie operacją „łańcuchową”, więc nadal warto mieć ją na str
obiekcie niż na różnych iteracjach.
-
oświadcza, że dołączasz do listy i konwertujesz na ciąg znaków, który jest zorientowany na wyniki.