На этом шаге мы рассмотрим разные способы выполнения этой операции.
Вам нужно объединить много небольших строк в длинную строку.
Если строки, которые вы хотите объединить, находятся в последовательности или итерируемом объекте, самый быстрый способ - использовать метод join(). Например:
>>> parts = ['Is', 'Chicago', 'Not', 'Chicago?'] >>> ' '.join(parts) 'Is Chicago Not Chicago?' >>> ','.join(parts) 'Is,Chicago,Not,Chicago?' >>> ''.join(parts) 'IsChicagoNotChicago?' >>>
На первый взгляд синтаксис может показаться странным, однако операция join() относится к строковым методам. Объекты, которые вы хотите объединить, могут приходить из разнообразных последовательностей данных (списки, кортежи, словари, файлы, множества или генераторы), поэтому было бы избыточным реализовывать метод join() для всех этих объектов. Так что вы просто задаете нужную строку-разделитель, а затем применяете метод join() для склеивания текстовых фрагментов.
Если вы просто объединяете несколько строк, неплохо сработает +:
>>> a = 'Is Chicago' >>> b = 'Not Chicago?' >>> a + ' ' + b 'Is Chicago Not Chicago?' >>>
Оператор + также отлично работает в качестве замены более сложным операциям форматирования строк. Например:
>>> print('{} {}'.format(a, b)) Is Chicago Not Chicago? >>> print(a + ' ' + b) Is Chicago Not Chicago? >>>
Если вы пытаетесь объединить строковые литералы в исходном коде, то можете просто разместить их рядом без использования оператора +. Например:
>>> a = 'Hello' 'World' >>> a 'HelloWorld' >>>
Объединение строк может показаться недостаточно сложным, чтобы писать про него целый рецепт, но часто эта область является критически важной для производительности.
Важно знать, что использование оператора + для объединения большого количества строк крайне неэффективно, поскольку в памяти создаются копии, что прибавляет работы сборщику мусора. Никогда не пишите такой код для объединения строк:
s = '' for p in parts: s += p
Это работает заметно медленнее метода join(), главным образом потому, что каждая += операция создает новый строковый объект. Намного лучше собрать все части и только затем объединить.
Еще один классный фокус из этой области - преобразование данных в строки и конкатенация с одновременным использованием выражения-генератора, как описано на 20 шаге. Например:
>>> data = ['ACME', 50, 91.1] >>> ','.join(str(d) for d in data) 'ACME,50,91.1' >>>
Берегитесь ненужной конкатенации. Иногда программисты применяют конкатенацию там, где это не нужно. Например:
print(a + ':' + b + ':' + c) # Плохо print(':'.join([a, b, c])) # Все еще плохо print(a, b, c, sep=':') # Лучше
Смешивание операций ввода-вывода и конкатенации строк - момент, с которым нужно быть очень внимательными. Например, рассмотрим два фрагмента кода:
# Версия 1 (конкатенация строк) f.write(chunk1 + chunk2) # Версия 2 (отдельные операции ввода-вывода) f.write(chunkl) f.write(chunk2)
Если две строки невелики, первая может предложить намного большую производительность (из-за дороговизны системного вызова ввода-вывода). Однако если строки велики, вторая версия может быть более эффективной, поскольку в этом случае не создается огромный промежуточный результат, а также не происходит копирования больших блоков памяти. Пробуйте на своих данных и выясняйте, что работает быстрее в вашем конкретном случае.
И последнее: если вы пишете код, который формирует результат из множества небольших строк, подумайте о том, чтобы оформить его как генератор, используя yield для производства фрагментов. Например:
def sample(): yield 'Is' yield 'Chicago' yield 'Not' yield 'Chicago?'
Интересно, что этот подход не делает предположений по поводу того, как фрагменты будут собираться вместе. Например, вы можете просто объединить фрагменты с помощью join():
text = ''.join(sample())
Или же вы можете перенаправить фрагменты на вывод:
for part in sample(): f.write(part)
Или же вы можете создать некую гибридную схему, что умно с точки зрения операций ввода-вывода:
def combine(source, maxsize): parts = [] size = 0 for part in source: parts.append(part) size += len(part) if size > maxsize: yield ''.join(parts) parts = [] size = 0 yield ''.join(parts) for part in combine(sample(), 32768): f.write(part)
Ключевой момент в том, что первоначальный генератор не обязан вникать в детали: он просто выдает части.
На следующем шаге мы рассмотрим интерполяцию переменных в строках.