Компиляция re.compile и производительность
Компилируем паттерн один раз и переиспользуем — это удобнее и иногда быстрее.
re.compile(pattern) превращает строку-паттерн в объект-шаблон с методами search, match, findall, sub.
Идея компиляции
Каждый вызов re.search(pattern, text) разбирает строку-паттерн заново (хотя у модуля есть внутренний кэш). Если один и тот же паттерн применяется много раз — например, в цикле по тысячам строк, — его удобно скомпилировать один раз в объект и дальше звать методы у него:
import re
number = re.compile(r"\d+")
print(number.findall("a1 b2 c3"))
print(number.search("цена 42 руб").group())
print(number.sub("#", "1 и 2 и 3"))
Вывод:
['1', '2', '3'] 42 # и # и #
У скомпилированного объекта те же методы (findall, search, sub...), только паттерн уже «вшит». Это устраняет повтор паттерна в каждом вызове.
Главная польза — читаемость
Компиляция придаёт паттерну имя. number.findall(text) читается лучше, чем безымянный \d+ в десятке мест. Паттерны собирают в одном месте (например, в начале модуля), документируют и переиспользуют — код становится опрятнее.
Про производительность
Модуль re кэширует последние использованные паттерны, поэтому для пары вызовов разница незаметна. Но в горячих циклах явная компиляция убирает накладные расходы на поиск в кэше и слегка ускоряет работу. Главное — не компилировать один и тот же паттерн заново внутри цикла:
import re
lines = ["id=10", "id=25", "нет числа", "id=7"]
rx = re.compile(r"id=(\d+)") # компилируем ОДИН раз
result = []
for line in lines:
m = rx.search(line)
if m:
result.append(int(m.group(1)))
print(result)
Вывод:
[10, 25, 7]
Паттерн id=(\d+) скомпилирован до цикла, а в теле цикла только применяется. Это и быстрее, и нагляднее.
Флаги при компиляции
Флаги передают вторым аргументом compile: re.compile(r"cat", re.IGNORECASE). После этого регистр учитываться не будет во всех вызовах объекта.
Итог
re.compileвозвращает объект-шаблон с методамиsearch,findall,subи др.- Главная польза — читаемость и переиспользование именованного паттерна.
- В горячих циклах компилируйте паттерн ОДИН раз снаружи, а внутри только применяйте.
- Флаги задают вторым аргументом:
re.compile(pattern, re.IGNORECASE).