2015-01-04 4 views
2

Пожалуйста, помогите мне понять, почему работает код в CODE2. Я понимаю, что re.compile возвращает объект, и мы задаем такие методы, как search, match, findall и т. Д., Чтобы получить желаемый результат.Смутно о поведении re.compile

В чем я смущен, так это то, как функции уровня модуля re, такие как поиск, могут принимать скомпилированный abject как параметр. Пожалуйста, смотрите Кодекса2

code1:

In [430]: p = re.compile(r'(\b\w+)\s+\1') 
In [431]: p.search('Paris in the the spring').group() 
Out[431]: 
'the the' 

КОД 2

In [432]: re.search(p, 'Paris in the the spring').group() 
Out[432]: 
'the the' 

ответ

3

re.search «s первым аргументом документирована как шаблон строки повторно, т.е. не скомпилированный объект RE - возможно, лучший дизайн должен был бы принять либо полиморфно, но, увы !, назад, когда разрабатывался модуль re, это просто не ho Мы сделали это. Ну что ж, по крайней мере, это так же по всем функциям модуля в re, которые имитируют методы re скомпилированных объектов -!)

Однако, в какой-то момент в долгой и легендарную историю Пайтона, кто-то фиксированный наш оригинальный рительных дизайн (я не могу сказать, когда это произошло!): в настоящее время, хотя для большинства функций re первый аргумент pattern по-прежнему считается строкой шаблона RE, некоторые из них теперь документируются как «может быть строкой или RE объект "... и все из них, кажется, работают так (лучше!).

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

Человек, хорошо, что я узнал об этом, когда я начинаю готовить (с двумя соавторами) третье издание «Python в двух словах» ... по крайней мере, я получу «исправить документы», для что! -)

Добавлено: для измерения скорости, как обычно, timeit - твой друг!

$ python -mtimeit -s'import re; s="paris in the spring"; mre=re.compile("paris")' 're.match("paris", s)' 
1000000 loops, best of 3: 1.38 usec per loop 

против:

$ python -mtimeit -s'import re; s="paris in the spring"; mre=re.compile("paris")' 'mre.match(s)' 
1000000 loops, best of 3: 0.468 usec per loop 

Итак, в целом, вы можете получить около 3 раза быстрее re.compile щих вещей сразу, чем пропускающий re функция обрабатывать все для вас. Посмотрите, почему я поклонник подхода re.compile? -)

Кроме того, в Python «более быстрый» имеет тенденцию сильно коррелировать с «более Pythonic» (другими словами, «идиоматический в Python»). Когда вы не знаете, какой из двух подошел, более Pythonic, timeit их правильно (желательно с использованием подхода командной строки python -mtimeit), и если любой из подходов надежно работает быстрее, у вас есть свой ответ: этот подход более Pythonic!-)

+0

Что означает «alas»? –

+0

В веб-поиске по 'define: alas', это« выражение горя, жалости или беспокойства ». Я фактически использовал его как выражение ** сожаления ** (за мою ответственность за возможную помощь в неправильном дизайне этого модуля, или, скорее, в том, что он может позволить пропустить неправильный дизайн - слишком поздно, чтобы изменить его сейчас!), Но Надеюсь, что это будет достаточно близко к «горе, жалости или беспокойству» (поскольку английский - это мой третий язык, я никогда не могу быть полностью уверен, правильно ли я его использую, хотя моя жена, родившаяся в Америке, и моя жена редакторы все поддерживают, я использую его лучше, чем большинство носителей языка ... :-). –

+0

Хорошо, английский - это не главное, поэтому я спросил :-) –

1

Все функции модуля re позволяют указать объект шаблона вместо строки шаблона. Это просто функция оптимизации/удобства, которая позволяет избежать создания нового объекта шаблона, если у вас его уже есть.


Я не смог найти ссылку DOCS, который явно упоминает это поведение, но вы можете увидеть его довольно легко, если вы просмотреть исходный код . Для начала, implementation для re.compile является:

def compile(pattern, flags=0): 
    "Compile a regular expression pattern, returning a pattern object." 
    return _compile(pattern, flags) 

Обратите внимание, как эта функция ничего не делает, но вызвать другую функцию с именем _compile. Эта функция фактически создает объект шаблона. re.compile - это просто псевдоним для него.


Двигаясь дальше, implementation для re.search является:

def search(pattern, string, flags=0): 
    """Scan through string looking for a match to the pattern, returning 
    a match object, or None if no match was found.""" 
    return _compile(pattern, flags).search(string) 

Как вы можете видеть, там тоже ничего особенного функции re.search. Он просто вызывает метод search объекта шаблона, возвращаемый re._compile. Это означает, что делает:

re.search(p, 'Paris in the the spring').group() 

так же, как:

re._compile(p).search('Paris in the the spring').group() 

Так что вопрос вы должны спрашивать, почему re._compile позволяет передать объект шаблона в виде строки шаблона. Как и раньше, ответ можно найти, посмотрев на implementation:

def _compile(pattern, flags): 
    ... 
    if isinstance(pattern, _pattern_type): 
     if flags: 
      raise ValueError(
       "Cannot process flags argument with a compiled pattern") 
     return pattern 

Как вы можете видеть, функция _compile делает проверку, чтобы увидеть, если его pattern аргумент уже объект шаблон. Если это так, он просто возвращает его и избегает создания нового. Это означает, что делает:

re.search(p, 'Paris in the the spring').group() 

эквивалентно:

re._compile(p).search('Paris in the the spring').group() 

, которая становится:

p.search('Paris in the the spring').group() 

Это исходный код для CPython.

Смежные вопросы