Почему это string.join(list)вместо list.join(string)?
Это потому, что joinэто «строковый» метод! Создает строку из любого итератора. Если мы поместим метод в списки, что делать, когда у нас есть итерации, которые не являются списками?
Что делать, если у вас есть набор строк? Если бы это был listметод, вам пришлось бы приводить каждый такой итератор строк как listпрежде, чем вы могли бы объединить элементы в одну строку! Например:
some_strings = ('foo', 'bar', 'baz')
Давайте свернем наш собственный метод соединения со списком:
class OurList(list):
def join(self, s):
return s.join(self)
И чтобы использовать его, обратите внимание, что мы должны сначала создать список из каждой итерации, чтобы объединить строки в эту итерацию, тратя впустую и память, и вычислительную мощность:
>>> l = OurList(some_strings) # step 1, create our list
>>> l.join(', ') # step 2, use our list join method!
'foo, bar, baz'
Итак, мы видим, что мы должны добавить дополнительный шаг, чтобы использовать наш метод списка, вместо того, чтобы просто использовать метод встроенной строки:
>>> ' | '.join(some_strings) # a single step!
'foo | bar | baz'
Предупреждение о производительности для генераторов
Алгоритм, который Python использует для создания окончательной строки, str.joinфактически должен дважды передавать итеративное значение, поэтому, если вы предоставите ему выражение генератора, он должен сначала материализовать его в список, прежде чем сможет создать окончательную строку.
Таким образом, хотя обход генераторов обычно лучше, чем списки, str.joinисключение:
>>> 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
Тем не менее, эта str.joinоперация все еще семантически является «строковой» операцией, поэтому все же имеет смысл иметь ее на strобъекте, а не на других итерациях.
-объявляет, что вы присоединяетесь к списку и конвертируете в строку. Она ориентирована на результат.