Компиляция регулярного выражения внутри функции, вызывающей несколько раз

Если вы компилируете регулярное выражение внутри функции, и эта функция вызывается несколько раз, Python перекомпилирует регулярное выражение каждый раз, или Python кэширует скомпилированное регулярное выражение (при условии, что регулярное выражение не изменяется)?

Например:

def contains_text_of_interest(line):
    r = re.compile(r"foo\dbar\d")  
    return r.match(line)

def parse_file(fname):
    for line in open(fname):
        if contains_text_of_interest(line):
           # Do something interesting

Ответы

Ответ 1

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

Ответ 2

Если вы хотите избежать накладных расходов на вызов re.compile() каждый раз, вы можете сделать:

def contains_text_of_interest(line, r = re.compile(r"foo\dbar\d")): 
    return r.match(line) 

Ответ 3

Почему бы вам просто не поместить внешние функции re.compile(на уровне модуля или класса), дать ему явное имя и просто использовать его? Такое регулярное выражение является своего рода константой, и вы можете относиться к нему одинаково.

MATCH_FOO_BAR = re.compile(r"foo\dbar\d")  

def contains_text_of_interest(line):
    return MATCH_FOO_BAR.match(line)

Ответ 4

Решение Dingo - это хороший вариант [редактировать: объяснение Ned Batchelder еще лучше], но вот еще один, который я считаю аккуратным: используйте закрытие! Если это звучит как "большое слово", не беспокойтесь. Концепция проста:

def make_matching_function():
    matcher = re.compile(r"foo\dbar\d")
    def f(line):
        return matcher.match(line)
    return f
contains_text_of_interest = make_matching_function()

make_matching_function вызывается только один раз, поэтому регулярное выражение компилируется только один раз. Функция f, которая присваивается contains_text_of_interest, знает о скомпилированном регулярном выражении matcher, потому что она находится в окружении и всегда будет знать об этом, даже если вы используете contains_text_of_interest где-то еще (что замыкает: код который принимает окружающий объем с ним).

Не самое питоническое решение этой проблемы, конечно. Но это хорошая идиома, чтобы иметь дело с твоим рукавом, потому что, когда настало время:)