Методы форматирования строк в Python

Время чтения: меньше 5 мин

Способы форматирования

Секция статьи "Способы форматирования"

В Python существует 5 способов форматирования строк:

  • Конкатенация;
  • Оператора %;
  • Модуль Template;
  • Метод format();
  • f-строки.

Конкатенация

Секция статьи "Конкатенация"

Конкатенация строк - операция, "склеивающая" несколько строк в одну. Грубый способ, который не советуют использовать на практике, т.к. на каждой итераций, интерпретатор Python создает новый строковый объект получая сложность алгоритма O(n^2). Однако на 2022 год, в последних версиях интерпретатора CPython (интерпретатор по умолчанию), этот момент оптимизирован в отличие от других интерпретаторов PyPy, Jython, IronPython, Cython, Psyco и т.д.

        
          
          print("Hello " + "John Doe" + "!")
          print("Hello " + "John Doe" + "!")

        
        
          
        
      

В случаях, когда надо превратить в строку массив значений, используйте метод join(), где сложность составит O(n)

        
          
          print("".join(["Hello ", "John Doe", "!"]))
          print("".join(["Hello ", "John Doe", "!"]))

        
        
          
        
      

Оператора %

Секция статьи "Оператора %"

Форматирование с помощью оператора %. Перешел из языка С

        
          
          print("Hello %s!" % "John Doe")
          print("Hello %s!" % "John Doe")

        
        
          
        
      

Модуль Template

Секция статьи "Модуль Template"

Форматирование с помощью модуля Template из основной библиотеки. Добавлен в версий 2.4 (PEP292) и являлся заменой оператору %.

        
          
          from string import Templatemy_string = Template("Hello $full_name!")print(my_string.substitute(full_name="John Doe"))
          from string import Template
my_string = Template("Hello $full_name!")
print(my_string.substitute(full_name="John Doe"))

        
        
          
        
      

Метод format()

Секция статьи "Метод format()"

Форматирование с помощью метода format(). Был добавлен уже в Python3

  • именованные метки:
        
          
          print("Hello {name}!".format(name="John Doe"))
          print("Hello {name}!".format(name="John Doe"))

        
        
          
        
      
  • позиционные метки:
        
          
          print("Hello {0}!".format("John Doe"))
          print("Hello {0}!".format("John Doe"))

        
        
          
        
      
  • без меток:
        
          
          print("Hello {}!".format("John Doe"))
          print("Hello {}!".format("John Doe"))

        
        
          
        
      

f-строки

Секция статьи "f-строки"

f-строки (formatted string). Появился с версий 3.6

        
          
          name: str = "John Doe"print(f"Hello {name}!")
          name: str = "John Doe"
print(f"Hello {name}!")

        
        
          
        
      

Вывод

Секция статьи "Вывод"

Проверим скорость форматирования различными способами:

        
          
          import timeitdef func1():    str1, str2, str3 = "text1", "text2", "text3"    result: str = "str1=%s, str2=%s, str3=%s" % (str1, str2, str3)def func2():    str1, str2, str3 = "text1", "text2", "text3"    result: str = "str1={}, str2={}, str3={}".format(str1, str2, str3)def func3():    str1, str2, str3 = "text1", "text2", "text3"    result: str = f"str1={str1}, str2={str2}, str3={str3}"times = []num_runs: int = 100duration = timeit.Timer(func1).timeit(number=num_runs)avg_duration = duration / num_runstimes.append(avg_duration * 1000)duration = timeit.Timer(func2).timeit(number=num_runs)avg_duration = duration / num_runstimes.append(avg_duration * 1000)duration = timeit.Timer(func3).timeit(number=num_runs)avg_duration = duration / num_runstimes.append(avg_duration * 1000)print(f"operator % => {times[0]} ms")print(f"method format() => {times[1]} ms")print(f"f-string => {times[2]} ms")
          import timeit

def func1():
    str1, str2, str3 = "text1", "text2", "text3"
    result: str = "str1=%s, str2=%s, str3=%s" % (str1, str2, str3)

def func2():
    str1, str2, str3 = "text1", "text2", "text3"
    result: str = "str1={}, str2={}, str3={}".format(str1, str2, str3)

def func3():
    str1, str2, str3 = "text1", "text2", "text3"
    result: str = f"str1={str1}, str2={str2}, str3={str3}"

times = []
num_runs: int = 100
duration = timeit.Timer(func1).timeit(number=num_runs)
avg_duration = duration / num_runs
times.append(avg_duration * 1000)

duration = timeit.Timer(func2).timeit(number=num_runs)
avg_duration = duration / num_runs
times.append(avg_duration * 1000)

duration = timeit.Timer(func3).timeit(number=num_runs)
avg_duration = duration / num_runs
times.append(avg_duration * 1000)

print(f"operator % => {times[0]} ms")
print(f"method format() => {times[1]} ms")
print(f"f-string => {times[2]} ms")

        
        
          
        
      

Результат:

operator % => 0.00025000000000000716 ms
method format() => 0.0002920000000000006 ms
f-string => 0.00017799999999998373 ms

В результате самым быстром способом форматирования строк, является f-строка.

Допустим ты хочешь соединить 3 слова "first" + " second" + " third" - это 3 разных объекта

  1. Первый "+", "first" + " second", будет создан новый объект "first second"
  2. Второй "+", "first second" + " third", снова будет создан новый объект "first second third"
    То есть получается от кол-ва слов, которые надо склеить, будет также увеличиваться кол-во объектов создаваемых в памяти программы

В случае с f-строками, интерпретатор пробежится по кол-во слов, которые следует склеить и создаст один новый объект. То есть сложность будет O(n), неважно сколько слов, на выходе будет один объект.