Pythonic и эффективный способ определения нескольких регулярных выражений для использования на многих итерациях - PullRequest
7 голосов
/ 28 марта 2012

В настоящее время я пишу скрипт на Python для обработки около 10000 входных документов.Основываясь на результатах выполнения скрипта, я заметил, что первые 400+ документов обрабатываются очень быстро, а затем скрипт замедляется, хотя все входные документы имеют примерно одинаковый размер.

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

Поскольку мой сценарий имеет около 10 различных функций, каждая из которых использует около 10–20 различных шаблонов регулярных выражений, я задаюсь вопросом, что было бы более эффективным способом избежать в Pythonперекомпилировать шаблоны регулярных выражений снова и снова (в Perl я мог бы просто включить модификатор //o).

Я предполагаю, что если я сохраню объекты регулярных выражений в отдельных функциях, используя

pattern = re.compile()

результирующий объект регулярного выражения не будет сохранен до следующего вызова функции для следующей итерации (каждая функция вызывается, но один раз для каждого документа).

Кажется, что создание глобального списка предварительно скомпилированных регулярных выраженийнепривлекательный вариант, так как мне нужно было бы хранить список регулярных выражений в другом месте моего кода, отличном от того места, где они фактически используются.

Есть ли здесь какой-нибудь совет относительно того, как аккуратно и эффективно справиться с этим?

Ответы [ 4 ]

10 голосов
/ 29 марта 2012

Модуль re кеширует скомпилированные шаблоны регулярных выражений.Кэш очищается, когда он достигает размера re._MAXCACHE, который по умолчанию равен 100. (Так как у вас есть 10 функций с 10-20 регулярными выражениями в каждой (т.е. 100-200 регулярных выражений), наблюдаемое замедление имеет смысл с очисткойкеш.)

Если вы согласны с изменением приватных переменных, быстрое и грязное исправление вашей программы может состоять в том, чтобы установить re._MAXCACHE на более высокое значение:

import re
re._MAXCACHE = 1000
5 голосов
/ 29 марта 2012

В прошлый раз, когда я смотрел, re.compile поддерживал довольно маленький кеш, а когда он заполнялся, просто очищал его.DIY без ограничений:

class MyRECache(object):
    def __init__(self):
        self.cache = {}
    def compile(self, regex_string):
        if regex_string not in self.cache:
            self.cache[regex_string] = re.compile(regex_string)
        return self.cache[regex_string]
2 голосов
/ 29 марта 2012

Скомпилированное регулярное выражение автоматически кэшируется re.compile, re.search и re.match, но максимальный размер кэша в Python 2.7 равен 100, поэтому вы переполняете кеш.

Создание глобального списка предварительно скомпилированных регулярных выражений кажется непривлекательным вариантом, поскольку мне нужно было бы хранить список регулярных выражений в другом месте в моем коде, чем то, где они фактически используются.

Вы можете определить их рядом с местом, где они используются: непосредственно перед функциями, которые их используют. Если вы повторно используете один и тот же RE в другом месте, было бы хорошей идеей определить его глобально, чтобы избежать необходимости изменять его в нескольких местах.

1 голос
/ 29 марта 2012

В духе «проще - лучше», я бы использовал небольшую вспомогательную функцию, подобную этой:

def rc(pattern, flags=0):
    key = pattern, flags
    if key not in rc.cache:
        rc.cache[key] = re.compile(pattern, flags)
    return rc.cache[key]

rc.cache = {}

Использование:

rc('[a-z]').sub...
rc('[a-z]').findall <- no compilation here

Я также рекомендую попробовать регулярное выражение . Среди многих других преимуществ по сравнению с запасом, его MAXCACHE по умолчанию равен 500 и не будет полностью отброшен при переполнении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...