- en
- Language: ru
- Documentation version: latest
Форматирование строк с помощью f-строк
В Python 3.6 добавился новый вариант форматирования строк - f-строки или интерполяция строк. F-строки позволяют не только подставлять какие-то значения в шаблон, но и позволяют выполнять вызовы функций, методов и т.п.
Во многих ситуациях f-строки удобней и проще использовать, чем format, кроме того, f-строки работают быстрее, чем format и другие методы форматирования строк.
Синтаксис
F-строки - это литерал строки с буквой f
перед ним. Внутри f-строки
в паре фигурных скобок указываются имена переменных, которые надо
подставить:
In [1]: ip = '10.1.1.1'
In [2]: mask = 24
In [3]: f"IP: {ip}, mask: {mask}"
Out[3]: 'IP: 10.1.1.1, mask: 24'
Аналогичный результат с format можно получить так:
``"IP: {ip}, mask: {mask}".format(ip=ip, mask=mask)``.
Очень важное отличие f-строк от format: f-строки это выражение, которое
выполняется, а не просто строка. То есть, в случае с ipython, как только
мы написали выражение и нажали Enter, оно выполнилось и вместо выражений
{ip}
и {mask}
подставились значения переменных.
Поэтому, например, нельзя сначала написать шаблон, а затем определить переменные, которые используются в шаблоне:
In [1]: f"IP: {ip}, mask: {mask}"
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-e6f8e01ac9c4> in <module>()
----> 1 f"IP: {ip}, mask: {mask}"
NameError: name 'ip' is not defined
Кроме подстановки значений переменных, в фигурных скобках можно писать выражения:
In [1]: octets = ['10', '1', '1', '1']
In [2]: mask = 24
In [3]: f"IP: {'.'.join(octets)}, mask: {mask}"
Out[3]: 'IP: 10.1.1.1, mask: 24'
После двоеточия в f-строках можно указывать те же значения, что и при использовании format:
In [9]: oct1, oct2, oct3, oct4 = [10, 1, 1, 1]
In [10]: print(f'''
...: IP address:
...: {oct1:<8} {oct2:<8} {oct3:<8} {oct4:<8}
...: {oct1:08b} {oct2:08b} {oct3:08b} {oct4:08b}''')
IP address:
10 1 1 1
00001010 00000001 00000001 00000001
Особенности использования f-строк
При использовании f-строк нельзя сначала создать шаблон, а затем его использовать, как при использовании format.
F-строка сразу выполняется и в нее подставляются значения переменных, которые должны быть определены ранее:
In [7]: ip = '10.1.1.1'
In [8]: mask = 24
In [9]: print(f"IP: {ip}, mask: {mask}")
IP: 10.1.1.1, mask: 24
Если необходимо подставить другие значения, надо создать новые переменные (с теми же именами) и снова написать f-строку:
In [11]: ip = '10.2.2.2'
In [12]: mask = 24
In [13]: print(f"IP: {ip}, mask: {mask}")
IP: 10.2.2.2, mask: 24
При использовании f-строк в циклах, f-строку надо писать в теле цикла, чтобы она «подхватывала» новые значения переменных на каждой итерации:
In [1]: ip_list = ['10.1.1.1/24', '10.2.2.2/24', '10.3.3.3/24']
In [2]: for ip_address in ip_list:
...: ip, mask = ip_address.split('/')
...: print(f"IP: {ip}, mask: {mask}")
...:
IP: 10.1.1.1, mask: 24
IP: 10.2.2.2, mask: 24
IP: 10.3.3.3, mask: 24
Примеры использования f-строк
Базовая подстановка переменных:
In [1]: intf_type = 'Gi'
In [2]: intf_name = '0/3'
In [3]: f'interface {intf_type}/{intf_name}'
Out[3]: 'interface Gi/0/3'
Выравнивание столбцами:
In [6]: topology = [['sw1', 'Gi0/1', 'r1', 'Gi0/2'],
...: ['sw1', 'Gi0/2', 'r2', 'Gi0/1'],
...: ['sw1', 'Gi0/3', 'r3', 'Gi0/0'],
...: ['sw1', 'Gi0/5', 'sw4', 'Gi0/2']]
...:
In [7]: for connection in topology:
...: l_device, l_port, r_device, r_port = connection
...: print(f'{l_device:10} {l_port:7} {r_device:10} {r_port:7}')
...:
sw1 Gi0/1 r1 Gi0/2
sw1 Gi0/2 r2 Gi0/1
sw1 Gi0/3 r3 Gi0/0
sw1 Gi0/5 sw4 Gi0/2
Ширина столбцов может быть указана через переменную:
In [6]: topology = [['sw1', 'Gi0/1', 'r1', 'Gi0/2'],
...: ['sw1', 'Gi0/2', 'r2', 'Gi0/1'],
...: ['sw1', 'Gi0/3', 'r3', 'Gi0/0'],
...: ['sw1', 'Gi0/5', 'sw4', 'Gi0/2']]
...:
In [7]: width = 10
In [8]: for connection in topology:
...: l_device, l_port, r_device, r_port = connection
...: print(f'{l_device:{width}} {l_port:{width}} {r_device:{width}} {r_port:{width}}')
...:
sw1 Gi0/1 r1 Gi0/2
sw1 Gi0/2 r2 Gi0/1
sw1 Gi0/3 r3 Gi0/0
sw1 Gi0/5 sw4 Gi0/2
Работа со словарями
In [1]: session_stats = {'done': 10, 'todo': 5}
In [2]: if session_stats['todo']:
...: print(f"Pomodoros done: {session_stats['done']}, TODO: {session_stats['todo']}")
...: else:
...: print(f"Good job! All {session_stats['done']} pomodoros done!")
...:
Pomodoros done: 10, TODO: 5
Вызов функции len внутри f-строки:
In [2]: topology = [['sw1', 'Gi0/1', 'r1', 'Gi0/2'],
...: ['sw1', 'Gi0/2', 'r2', 'Gi0/1'],
...: ['sw1', 'Gi0/3', 'r3', 'Gi0/0'],
...: ['sw1', 'Gi0/5', 'sw4', 'Gi0/2']]
...:
In [3]: print(f'Количество подключений в топологии: {len(topology)}')
Количество подключений в топологии: 4
Вызов метода upper внутри f-строки:
In [1]: name = 'python'
In [2]: print(f'Zen of {name.upper()}')
Zen of PYTHON
Конвертация чисел в двоичный формат:
In [7]: ip = '10.1.1.1'
In [8]: oct1, oct2, oct3, oct4 = ip.split('.')
In [9]: print(f'{int(oct1):08b} {int(oct2):08b} {int(oct3):08b} {int(oct4):08b}')
00001010 00000001 00000001 00000001
Что использовать format или f-строки
Во многих случаях f-строки удобней использовать, так как шаблон выглядит понятней и компактней. Однако бывают случаи, когда метод format удобней. Например:
In [6]: ip = [10, 1, 1, 1]
In [7]: oct1, oct2, oct3, oct4 = ip
...: print(f'{oct1:08b} {oct2:08b} {oct3:08b} {oct4:08b}')
...:
00001010 00000001 00000001 00000001
In [8]: template = "{:08b} "*4
In [9]: template.format(*ip)
Out[9]: '00001010 00000001 00000001 00000001 '
Еще одна ситуация, когда format, как правило, удобней использовать: необходимость использовать в скрипте один и тот же шаблон много раз. F-строка выполнится первый раз и подставит текущие значения переменных и для использования шаблона еще раз, его надо заново писать. Это значит, что в скрипте будут находится копии одной и то же строки. В то же время format позволяет создать шаблон в одном месте и потом использовать его повторно, подставляя переменные по мере необходимости.
Это можно обойти создав функцию, но создавать функцию для вывода строки по шаблону далеко не всегда оправдано. Пример создания функции:
In [1]: def show_me_ip(ip, mask):
...: return f"IP: {ip}, mask: {mask}"
...:
In [2]: show_me_ip('10.1.1.1', 24)
Out[2]: 'IP: 10.1.1.1, mask: 24'
In [3]: show_me_ip('192.16.10.192', 28)
Out[3]: 'IP: 192.16.10.192, mask: 28'