Python предлагает несколько подходов к форматированию строк. В этой статье разберём продвинутые возможности f-строк, мини-язык форматирования, шаблоны и новые template strings из Python 3.14.
f-строки: продвинутые техники
Вложенные выражения
# Any valid expression inside braces
import math
radius = 5
print(f"Площадь круга: {math.pi * radius ** 2:.2f}") # 78.54
# Conditional expressions
score = 85
print(f"Результат: {'сдал' if score >= 60 else 'не сдал'}")
# Method calls
name = "иван петров"
print(f"Имя: {name.title()}") # Имя: Иван Петров
# Dictionary access
user = {"name": "Иван", "age": 25}
print(f"Имя: {user['name']}, Возраст: {user['age']}")
# List comprehension inside f-string
nums = [1, 2, 3, 4, 5]
print(f"Квадраты: {[x**2 for x in nums]}")
# Квадраты: [1, 4, 9, 16, 25]
# Walrus operator inside f-string
data = [10, 20, 30]
print(f"Сумма: {(total := sum(data))}, Среднее: {total / len(data)}")
# Сумма: 60, Среднее: 20.0
Отладочный формат (=)
# Debug format - shows expression = value
x = 42
y = 3.14
name = "Python"
print(f"{x = }") # x = 42
print(f"{y = :.1f}") # y = 3.1
print(f"{name = !r}") # name = 'Python'
print(f"{name = !s}") # name = Python
print(f"{x * y = :.2f}") # x * y = 131.88
print(f"{len(name) = }") # len(name) = 6
# Preserves whitespace around =
print(f"{x=}") # x=42
print(f"{x = }") # x = 42
print(f"{ x = }") # x = 42 (outer spaces stripped)
# Useful for debugging complex expressions
items = {"apple": 3, "banana": 5}
print(f"{items.get('apple', 0) = }")
# items.get('apple', 0) = 3
Мини-язык форматирования (Format Specification)
Полный синтаксис спецификатора формата:
[[fill]align][sign][z][#][0][width][grouping_option][.precision][type]
Выравнивание и заполнение
text = "Python"
# Alignment: < left, > right, ^ center, = pad after sign
print(f"|{text:<20}|") # |Python |
print(f"|{text:>20}|") # | Python|
print(f"|{text:^20}|") # | Python |
print(f"|{text:*^20}|") # |*******Python*******|
print(f"|{text:.<20}|") # |Python..............|
# Numeric alignment
n = -42
print(f"{n:>10}") # ' -42'
print(f"{n:=10}") # '- 42' (pad between sign and digits)
print(f"{n:010}") # '-000000042' (zero-fill)
Знак числа
# Sign options: +, -, space
n = 42
print(f"{n:+}") # '+42' (always show sign)
print(f"{-n:+}") # '-42'
print(f"{n:-}") # '42' (show sign only for negative, default)
print(f"{n: }") # ' 42' (space for positive, minus for negative)
print(f"{-n: }") # '-42'
# Useful for tables
values = [10, -5, 0, 23, -17]
for v in values:
print(f"{v:+5d}")
# +10
# -5
# +0
# +23
# -17
Числовые форматы
n = 1234567
# Grouping
print(f"{n:,}") # '1,234,567' (comma separator)
print(f"{n:_}") # '1_234_567' (underscore separator)
# Different bases
x = 255
print(f"{x:b}") # '11111111' (binary)
print(f"{x:o}") # '377' (octal)
print(f"{x:x}") # 'ff' (hex lowercase)
print(f"{x:X}") # 'FF' (hex uppercase)
print(f"{x:#b}") # '0b11111111' (with prefix)
print(f"{x:#o}") # '0o377'
print(f"{x:#x}") # '0xff'
# Float formats
pi = 3.14159265
print(f"{pi:f}") # '3.141593' (fixed-point, default 6 decimals)
print(f"{pi:.2f}") # '3.14'
print(f"{pi:e}") # '3.141593e+00' (scientific notation)
print(f"{pi:.3e}") # '3.142e+00'
print(f"{pi:g}") # '3.14159' (general: removes trailing zeros)
print(f"{pi:.10g}") # '3.14159265'
# Percentage
ratio = 0.8567
print(f"{ratio:.1%}") # '85.7%'
print(f"{ratio:.0%}") # '86%'
# Python 3.14: z flag for negative zero
val = -0.0
print(f"{val:z.1f}") # '0.0' (not '-0.0')
Динамические спецификаторы
# Width and precision as variables
width = 15
precision = 3
value = 3.14159
print(f"{value:{width}.{precision}f}") # ' 3.142'
# Dynamic alignment
for align in "<>^":
print(f"{' Python ':{align}20}")
# Dynamic fill character
fill = "="
print(f"{'Title':{fill}^30}") # ============Title=============
# Reusable format specs
money_fmt = ",.2f"
print(f"Зарплата: {50000:>{money_fmt}} руб.") # Зарплата: 50,000.00 руб.
format() и format()
# Built-in format() function
print(format(42, "08b")) # '00101010'
print(format(3.14, ".5f")) # '3.14000'
print(format(1000000, ",")) # '1,000,000'
# Custom __format__ in classes
class Temperature:
def __init__(self, celsius: float):
self.celsius = celsius
def __format__(self, spec: str) -> str:
match spec:
case "c":
return f"{self.celsius:.1f}°C"
case "f":
return f"{self.celsius * 9/5 + 32:.1f}°F"
case "k":
return f"{self.celsius + 273.15:.1f}K"
case _:
return f"{self.celsius:.1f}°C"
temp = Temperature(36.6)
print(f"Температура: {temp:c}") # Температура: 36.6°C
print(f"Температура: {temp:f}") # Температура: 97.9°F
print(f"Температура: {temp:k}") # Температура: 309.8K
string.Template
string.Template -- более простой и безопасный способ шаблонирования:
from string import Template
# Basic template substitution
tmpl = Template("Привет, $name! Вам $age лет.")
result = tmpl.substitute(name="Иван", age=25)
print(result) # Привет, Иван! Вам 25 лет.
# safe_substitute - no errors for missing keys
tmpl = Template("$greeting, $name!")
result = tmpl.safe_substitute(greeting="Привет")
print(result) # Привет, $name! (missing key kept as-is)
# Braces for ambiguous cases
tmpl = Template("${noun}ification")
print(tmpl.substitute(noun="mod")) # modification
# Useful for user-provided templates (safer than f-strings)
user_template = Template("Заказ #$order_id: $product x $quantity")
print(user_template.substitute(
order_id="1234",
product="Python Book",
quantity=2
))
Template strings (t-строки) -- Python 3.14
PEP 750 вводит новый тип строк с префиксом t"":
# t-strings create Template objects, not strings
from string.templatelib import Template, Interpolation
name = "Иван"
age = 25
# t-string syntax (identical to f-string)
tmpl = t"Привет, {name}! Вам {age} лет."
# tmpl is a Template object, NOT a string
# Template contains args - static parts and interpolations
# Process template programmatically
def render(template) -> str:
"""Render template to string."""
parts = []
for arg in template.args:
if isinstance(arg, str):
parts.append(arg)
elif isinstance(arg, Interpolation):
parts.append(str(arg.value))
return "".join(parts)
print(render(tmpl)) # Привет, Иван! Вам 25 лет.
Безопасные SQL-запросы с t-строками
# Safe SQL query building with t-strings
def sql_query(template) -> tuple[str, list]:
"""Convert t-string to parameterized SQL query."""
query_parts = []
params = []
for arg in template.args:
if isinstance(arg, str):
query_parts.append(arg)
elif isinstance(arg, Interpolation):
query_parts.append("?")
params.append(arg.value)
return "".join(query_parts), params
user_id = 42
username = "admin'; DROP TABLE users;--"
query, params = sql_query(t"SELECT * FROM users WHERE id = {user_id} AND name = {username}")
print(query) # SELECT * FROM users WHERE id = ? AND name = ?
print(params) # [42, "admin'; DROP TABLE users;--"]
# SQL injection prevented!
HTML-шаблонирование с t-строками
import html
def render_html(template) -> str:
"""Render t-string with HTML escaping."""
parts = []
for arg in template.args:
if isinstance(arg, str):
parts.append(arg)
elif isinstance(arg, Interpolation):
# Escape all interpolated values
parts.append(html.escape(str(arg.value)))
return "".join(parts)
user_comment = '<script>alert("XSS")</script>'
safe = render_html(t"<div class='comment'>{user_comment}</div>")
print(safe)
# <div class='comment'><script>alert("XSS")</script></div>
Сравнение подходов
name = "Иван"
age = 25
# 1. %-formatting (старый стиль, не рекомендуется)
print("Имя: %s, Возраст: %d" % (name, age))
# 2. str.format() (совместимость с Python 2)
print("Имя: {}, Возраст: {}".format(name, age))
# 3. f-strings (предпочтительный способ, Python 3.6+)
print(f"Имя: {name}, Возраст: {age}")
# 4. string.Template (пользовательские шаблоны)
from string import Template
print(Template("Имя: $name, Возраст: $age").substitute(name=name, age=age))
# 5. t-strings (Python 3.14+, безопасное шаблонирование)
# tmpl = t"Имя: {name}, Возраст: {age}"
# Performance comparison (f-strings are fastest):
# f-string ~100ns
# format() ~250ns
# % ~200ns
# Template ~1000ns
Таблица форматов чисел
# Quick reference for number formatting
n = 42
pi = 3.14159
formats = [
(f"{n:d}", "Десятичное целое"),
(f"{n:05d}", "С ведущими нулями"),
(f"{n:+d}", "С обязательным знаком"),
(f"{n:b}", "Двоичное"),
(f"{n:o}", "Восьмеричное"),
(f"{n:x}", "Шестнадцатеричное"),
(f"{pi:.2f}", "Фиксированная точка"),
(f"{pi:.2e}", "Научная нотация"),
(f"{pi:.4g}", "Общий формат"),
(f"{0.856:.1%}", "Проценты"),
(f"{1234567:,}", "С разделителем тысяч"),
]
print(f"{'Формат':<15} {'Описание':<30}")
print("-" * 45)
for fmt, desc in formats:
print(f"{fmt:<15} {desc:<30}")
Итоги
- f-строки -- основной инструмент форматирования (быстрый, читаемый)
- Оператор
=в f-строках показывает имя и значение выражения - Мини-язык форматирования:
{value:fill align sign # 0 width , .precision type} __format__()позволяет определить пользовательское форматированиеstring.Template-- безопасен для пользовательских шаблонов- t-строки (Python 3.14) -- безопасное шаблонирование для SQL, HTML и других контекстов
- Флаг
z(Python 3.14) -- устраняет отрицательный ноль при форматировании