f-Строки Python

Основы

Не смотря на один из принципов Python, гласящий: «Должен существовать один — и, желательно, только один – очевидный способ сделать что-то», в нашем любимом языке есть аж четыре способа отформатировать строку. Так сложилось исторически.
Это второй урок цикла, посвящённого форматированию строк. В него входят:

  1. Строковый оператор форматирования
  2. Метод format()
  3. f-Строки
  4. Шаблонные строки

В данном уроке мы познакомимся с f-Строками.
В Python 3.6 появился новый способ форматирования строки – интерполяция строк (чаще называют «форматированные строковые литералы» или «f-Строки»).
f-Строки предоставляют возможность использовать выражения Питона внутри строк. Происходит это следующим образом: каждое выражение вычисляется, затем все части f-Строки отдельно преобразуется в обычные строки, затем все части конкатенируются (склеиваются в одну). Форматированные строковые литералы так же, как и описанный в предыдущем уроке метод строки .format(), поддерживают форматирование, описанное в атрибуте __format__ . Узнать f-Строки Вы можете по символу «f» в начале строки перед открывающей кавычкой.

Простой синтаксис

Для того, чтобы использовать форматированные строковые литералы, просто поставьте символ «f» перед строкой и укажите в ней в фигурных скобках выражения Питона. В простейшем случае это имена переменных. Python, как всегда, радует своей лаконичностью! Пример:

язык = 'Python'
проценты = 100
print(f'-Самый лучший язык - {язык}.\n'
    f'-Точно?\n'
    f'-{проценты}%!')
# Вывод:
-Самый лучший язык - Python.
-Точно?
-100%!


Как видите, форматированные строковые литералы могут быть многострочными, но символ «f» должен быть в начале каждой строки.
Если Вы используете заглавную «F» — интерпретатор всё равно Вас поймёт:

print(F'2 + 2 = {2 + 2}')
# Вывод:
2 + 2 = 4


Надеюсь, Вы в таком же восторге от этого синтаксиса, как и я!

Произвольные выражения

Обратите внимание, в предыдущем примере мы использовали в строке выражение {2 + 2}. Оно сперва вычисляется, а затем преобразуется в строку. Это, конечно, открывает большие возможности.

my_var = input('Введи и я умножу ')

print(f'{(my_var + " ") * 2}')
# Вывод:
Введи и я умножу Hello!
Hello! Hello!


Также вы можете вызывать функции. Вот упрощённое решение задачи из урока про input():

первое_число = int(input('Введите число '))
первый_знак = input('Введите знак ')
второе_число = int(input('Введите число '))
второй_знак = input('Введите знак ')
третье_число = int(input('Введите число '))

def calculate(first_digit, operator, second_digit):
    if operator == '+':
        return first_digit + second_digit
    if operator == '-':
        return first_digit - second_digit
    if operator == '*':
        return first_digit * second_digit
    if operator == '/':
        try:
            return first_digit / second_digit
        except ZeroDivisionError:
            print('Делить на ноль нельзя - это опасно!')

print(f'{calculate(calculate(первое_число, первый_знак, второе_число), второй_знак, третье_число)}')
# Вывод:
Введите число 2
Введите знак +
Введите число 2
Введите знак /
Введите число 3
1.3333333333333333


Обратите внимание, это упрощённое решение. Здесь нет проверки на очерёдность выполнения арифметических действий, проверки на то, что введено цело число и т. д. Разработку этих деталей оставляю Вам для самостоятельной работы.
Также вы можете вызывать методы объектов:

my_var = input('Введи и я умножу ')

print(f'{(my_var + " ").split() * 2}')
# Вывод:
Введи и я разделю Hello!
['Hello!', 'Hello!']


Вы даже можете использовать объекты, созданные из классов при помощи f-строки.

class Foo:
    pass

print(f'{Foo()} is instance of {Foo}')
# Вывод:
<__main__.Foo object at 0x000002425BE70E50> is instance of <class '__main__.Foo'>


Давайте разберёмся, что здесь происходит. Когда Вы пытаетесь распечатать объект, интерпретатор обращается к его методам __str__() и __repr__(). Мы можем переопределить один из них и получить красивый вывод:

class Foo:
    def __str__(self):
        return 'Foo object'

print(f'{Foo()} is instance of {Foo}')
# Вывод:
Foo object is instance of <class '__main__.Foo'>

Многострочные F-Strings

Как уже говорилось, у вас могут быть многострочные f-strings, но, если Вы забудете поставить «f» в начале каждой строки, Вы получите совсем не то, чего ожидали:

print(f'1 + 1 = {1 + 1}\n'
    '2 + 2 = {2 + 2}')
# Вывод:
1 + 1 = 2
2 + 2 = {2 + 2}


Но у Вас есть возможность использовать «f» перед тройными кавычками, тогда всё сработает:

print(f"""1 + 1 = {1 + 1}
2 + 2 = {2 + 2}""")
# Вывод:
1 + 1 = 2
2 + 2 = 4

Скорость

Одной из целей создания форматированных строковых литералов являлось увеличение скорости по сравнению с, уже существовавшим на тот момент, методом строки .format(). И это цель была достигнута. Давайте проверим это утверждение:

import timeit

var_1 = timeit.timeit("""
язык = 'Python'
проценты = 100
'-Самый лучший язык - %s. -Точно? -%d' % (язык, проценты) + '%!'
""", number=10000)
var_2 = timeit.timeit("""
язык = 'Python'
проценты = 100
'-Самый лучший язык - {}. -Точно? {}'.format(язык, проценты) + '%!'
""", number=10000)
var_3 = timeit.timeit("""
язык = 'Python'
проценты = 100
f'-Самый лучший язык - {язык}. -Точно? {проценты}' + '%!'
""", number=10000)
var_4 = timeit.timeit("""
язык = 'Python'
проценты = 100
'-Самый лучший язык - ' + язык + '. -Точно? ' + str(проценты) + '%!'
""", number=10000)
time_sum = var_1 + var_2 + var_3 + var_4
var_1, var_2, var_3, var_4 = [round(i / time_sum * 100) for i in (var_1, var_2, var_3, var_4)]
print('Строковый оператор форматирования: ', var_1, '%', sep='')
print('Метод .format(): ', var_2, '%', sep='')
print('Форматированный строковый литерал: ', var_3, '%', sep='')
print('Конкатенация: ', var_4, '%', sep='')
# Вывод:
Строковый оператор форматирования: 26%
Метод .format(): 31%
Форматированный строковый литерал: 17%
Конкатенация: 27%


Конкатенация здесь приведена просто для наглядности. Как видите, «f»-Строки выигрывают в скорости.
При добавлении циклов вызова, разница остаётся такой же:

import timeit

var_2 = timeit.timeit("""
язык = 'Python'
проценты = 100
'-Самый лучший язык - {}. -Точно? {}'.format(язык, проценты) + '%!'
""", number=10000000)
var_3 = timeit.timeit("""
язык = 'Python'
проценты = 100
f'-Самый лучший язык - {язык}. -Точно? {проценты}' + '%!'
""", number=10000000)

time_sum = var_2 + var_3
var_2, var_3 = [round(i / time_sum * 100) for i in (var_2, var_3)]

print('Метод .format(): ', var_2, '%', sep='')
print('Форматированный строковый литерал: ', var_3, '%', sep='')
# Вывод:
Метод .format(): 65%
Форматированный строковый литерал: 35%

Python F-Строки: Детали

На данный момент мы узнали почему f-строки так хороши, так что вам уже может быть интересно их попробовать в работе. Рассмотрим несколько деталей, которые нужно учитывать:

Кавычки

Вы можете использовать несколько видов кавычек внутри выражений. Удостоверьтесь в том, что вы не применяете один и тот же тип кавычек внутри и снаружи f-строки.
Этот код будет работать:


И этот тоже:

Вы также можете применить тройные кавычки:

print(f"""{"Python"}""")
# Вывод:
Python


Если вам понадобиться использовать один и тот же тип кавычек внутри и снаружи строки, вам может помочь \:

print(f'\'Lorem\' \'ipsum\' \'dolor\' \'sit\' \'amet\'')
# Вывод:
'Lorem' 'ipsum' 'dolor' 'sit' 'amet'

Словари

Говоря о кавычках, будьте внимательны при работе со словарями Python. Вы можете вставить значение словаря по его ключу, но ключ и сама строка должны быть обрамлены разными кавычками:

arg_dict = {'язык': 'Python', 'проценты': 100}

print(f"-Самый лучший язык - {arg_dict['язык']}.\n"
    f"-Точно?\n"
    f"-{arg_dict['проценты']}%!")
# Вывод:
-Самый лучший язык - Python.
-Точно?
-100%!


Обратите внимание на количество возможных проблем, если допустить ошибку в синтаксисе SyntaxError:

arg_dict = {'язык': 'Python', 'проценты': 100}

print(f'-Самый лучший язык - {arg_dict['язык']}.\n'
    f'-Точно?\n'
    f'-{arg_dict['проценты']}%!')
# Вывод:
File "C:\Users\ivand\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_1.py", line 3
print(f'-Самый лучший язык - {arg_dict['язык']}.\n'
                             ^
SyntaxError: f-string: unmatched '['

Process finished with exit code 1

Скобки

Чтобы скобки появились в строке, вам нужно использовать двойные фигурные скобки:

print(f'-Самый лучший язык - {{Python}}.\n'
    f'-Точно?\n'
    f'-{{100}}%!')
# Вывод:
-Самый лучший язык - {Python}.
-Точно?
-{100}%!


Обратите внимание на то, что применение тройных фигурных скобок приведет к тому, что в строке будут только одинарные:

В целом, здесь мы имеем такое же неочевидное поведение, как и у метода строки .format():

print(f'{{{{{{{{1}}}}}}}}')
# Вывод:
{{{{1}}}}

Бэкслеши

Несмотря на то, что бэкслеш можно использовать в строке, у Вас не получится сделать это внутри выражения:

print(f'{"1\n2"}')
# Вывод:
File "C:\Users\ivand\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_1.py", line 1
print(f'{"1\n2"}')
           ^
SyntaxError: f-string expression part cannot include a backslash

Process finished with exit code 1


Вы можете проработать это, оценивая выражение заранее и используя результат в f-строк:

temp = "1\n2"
print(f'{temp}')
# Вывод:
1
2

Междустрочные комментарии

Выражения не должны содержать комментарии с применением октоторпа (символ «#»). В противном случае, у вас будет ошибка синтаксиса SyntaxError:

print(f'2 + 2 = {4 # наверно}')
# Вывод:
File "C:\Users\ivand\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_1.py", line 1
print(f'2 + 2 = {4 # наверно}')
                   ^
SyntaxError: f-string expression part cannot include '#'

Process finished with exit code 1

Форматирование вставляемых выражений

Форматированные строковые литералы, как и метод строки .format() поддерживают форматирование:

print(f'2 + 2 = {2 + 2:010d}')
# Вывод:
2 + 2 = 0000000004
print(f'2 + 2 = {2 + 2:^010d}')
# Вывод:
2 + 2 = 0000400000
print(f'2 + 2 = {"четыре":.3}')
# Вывод:
2 + 2 = чет
заполнитель = '_'
выравнивание = '^'
ширина = 9
язык = 'Питон'
print(f"{язык:{заполнитель}{выравнивание}{ширина}}")
# Вывод:
__Питон__


Подробнее об этом читайте в нашем предыдущем уроке.

Оцените статью
О Python на русском языке
Добавить комментарий

Adblock
detector