Dlaczego jest to string.join(list)zamiast list.join(string)?
Jest tak, ponieważ joinjest 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 listmetoda, musiałbyś rzucić każdy taki iterator ciągów, listzanim 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.joinfaktycznie 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.joinjest 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.joinoperacja jest nadal semantycznie operacją „łańcuchową”, więc nadal warto mieć ją na strobiekcie 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.