Формат строки против конкатенации

Я вижу много людей, использующих строки формата, например:

root = "sample"
output = "output"
path = "{}/{}".format(root, output)

Вместо простого объединения строк вот так:

path = root + '/' + output

Строки форматирования имеют лучшую производительность или это только для внешнего вида?

 Dawid Ferenczy Rogožan02 авг. 2016 г., 15:44
 doublep02 авг. 2016 г., 15:43
Я предполагаю, что у них хуже показатели. Но я все еще предпочитаю строки формата в местах, не критичных к производительности.

Ответы на вопрос(7)

Это для внешнего вида и поддержания кода. Редактировать код действительно проще, если вы используете формат. Также, когда вы используете +, вы можете пропустить детали, такие как пробелы. Используйте формат для вашего и возможных сопровождающих.

конкатенации, мы должны набрать приведение или преобразовать данные соответственно.

Например:

a = 10
b = "foo"
c = str(a) + " " + b
print c
> 10 foo

Это можно сделать с помощью форматирования строки:

a = 10
b = "foo"
c = "{} {}".format(a, b)
print c
> 10 foo

Такой что с-в заполнителях{} {}, мы предполагаем, что две вещи идут дальше, то есть в этом случаеa а такжеb.

 edanfalls27 апр. 2019 г., 20:50
@ Берт Иногда это недостаток - вы можете захотетьTypeError размножаться от конкатенации. Так что если использовать.format вместо этого вам нужно будет заранее добавить дополнительную проверку типов. Поэтому я думаю, что лучше рассмотреть это в каждом конкретном случае. Я использую оба метода, вероятно, равное количество.
 Bert25 мар. 2018 г., 01:54
Это причина, по которой я бы использовал.format, это позволяет избежать ошибок, таких какCannot concatenate 'str' and 'int' objects

что форматирование в основном используется для удобства чтения, но после выпуска f-строк в версии 3.6 таблицы изменились с точки зрения производительности. Я также считаю, что f-строки более читабельны / удобны в обслуживании, поскольку 1) их можно читать влево-вправо, как и в большинстве обычных текстов, и 2) избегаются недостатки конкатенации, связанные с пробелами, поскольку переменные являются строковыми.

Запуск этого кода:

from timeit import timeit

runs = 1000000


def print_results(time, start_string):
    print(f'{start_string}\n'
          f'Total: {time:.4f}s\n'
          f'Avg: {(time/runs)*1000000000:.4f}ns\n')


t1 = timeit('"%s, %s" % (greeting, loc)',
            setup='greeting="hello";loc="world"',
            number=runs)
t2 = timeit('f"{greeting}, {loc}"',
            setup='greeting="hello";loc="world"',
            number=runs)
t3 = timeit('greeting + ", " + loc',
            setup='greeting="hello";loc="world"',
            number=runs)
t4 = timeit('"{}, {}".format(greeting, loc)',
            setup='greeting="hello";loc="world"',
            number=runs)

print_results(t1, '% replacement')
print_results(t2, 'f strings')
print_results(t3, 'concatenation')
print_results(t4, '.format method')

дает такой результат на моей машине:

% replacement
Total: 0.3044s
Avg: 304.3638ns

f strings
Total: 0.0991s
Avg: 99.0777ns

concatenation
Total: 0.1252s
Avg: 125.2442ns

.format method
Total: 0.3483s
Avg: 348.2690ns

Аналогичный ответ на другой вопрос дан наэтот ответ.

Решение Вопроса

что это за формат. Многим из нас нравится читаемость лучше, чем микрооптимизация.

Давайте посмотрим, что IPython%timeit говорит:

Python 3.7.2 (default, Jan  3 2019, 02:55:40)
IPython 5.8.0
Intel(R) Core(TM) i5-4590T CPU @ 2.00GHz

In [1]: %timeit root = "sample"; output = "output"; path = "{}/{}".format(root, output)
The slowest run took 12.44 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 5: 223 ns per loop

In [2]: %timeit root = "sample"; output = "output"; path = root + '/' + output
The slowest run took 13.82 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 5: 101 ns per loop

In [3]: %timeit root = "sample"; output = "output"; path = "%s/%s" % (root, output)
The slowest run took 27.97 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 5: 155 ns per loop

In [4]: %timeit root = "sample"; output = "output"; path = f"{root}/{output}"
The slowest run took 19.52 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 5: 77.8 ns per loop
 Wyrmwood25 июн. 2018 г., 19:57
@ Comte вам нужно f перед ним, но да.
 comte21 нояб. 2017 г., 12:15
Обратите внимание, что начиная с Python 3.6, вы можете использовать path = "{root} / {output}", что довольно просто ...

будет разница в производительности, но спросите себя: «Действительно ли это важно, если это быстрее?».root + '/' output метод быстрый и простой в наборе. Но это может быть трудно читать очень быстро, когда у вас есть несколько переменных для печати

foo = "X = " + myX + " | Y = " + someY + " Z = " + Z.toString()

против

foo = "X = {} | Y= {} | Z = {}".format(myX, someY, Z.toString())

Что легче понять, что происходит? Если только ты недействительно нужно повысить производительность, выбрать способ, который будет проще для людей, чтобы читать и понимать

й типов; это также необходимо для интернационализации.

Вы можете поменять строку формата в зависимости от того, какой язык выбран.

С длинной строкой конкатенации строк, вставленной в исходный код, это становится практически невозможным для правильного выполнения.

Начиная с Python 3.6 вы можете сделатьинтерполяция литеральной строки подготовивf к строке:

root = "sample"
output = "output"
path = f"{root}/{output}"

Ваш ответ на вопрос