Y a-t-il un avantage à utiliser compile pour les expressions régulières en Python?
h = re.compile('hello')
h.match('hello world')
contre
re.match('hello', 'hello world')
Y a-t-il un avantage à utiliser compile pour les expressions régulières en Python?
h = re.compile('hello')
h.match('hello world')
contre
re.match('hello', 'hello world')
J'ai eu beaucoup d'expérience en cours d'exécution, constitué à partir des regex 1000s de fois contre la compilation à la volée, et n'ai pas remarqué de différence perceptible. Évidemment, c'est familier, et certainement pas un grand argument à l'encontre de la compilation, mais j'ai trouvé la différence sera négligeable.
EDIT:
Après un rapide coup d'œil à l'Python 2.5 bibliothèque de code, je vois que Python en interne, les compile ET les CACHES regexes chaque fois que vous les utiliser de toute façon (y compris les appels à l' re.match()
), de sorte que vous êtes vraiment en changeant uniquement LORSQUE la regex sera compilé, et ne devrait pas être de sauver beaucoup de temps, seulement le temps qu'il faut pour vérifier le cache (une clé de recherche à l'interne en dict
type).
De module re.py (les commentaires sont de la mienne):
def match(pattern, string, flags=0):
return _compile(pattern, flags).match(string)
def _compile(*key):
# Does cache check at top of function
cachekey = (type(key[0]),) + key
p = _cache.get(cachekey)
if p is not None: return p
# ...
# Does actual compilation on cache miss
# ...
# Caches compiled regex
if len(_cache) >= _MAXCACHE:
_cache.clear()
_cache[cachekey] = p
return p
J'ai encore souvent des pré-compilation des expressions régulières, mais seulement pour les lier à une belle, réutilisable nom, pas pour tout gain de performance.
FWIW:
$ python -m timeit -s "import re" "re.match('hello', 'hello world')"
100000 loops, best of 3: 3.82 usec per loop
$ python -m timeit -s "import re; h=re.compile('hello')" "h.match('hello world')"
1000000 loops, best of 3: 1.26 usec per loop
Donc, si vous utilisez beaucoup la même regex, ça vaut la peine de faire re.compile
(surtout pour les regex plus complexes).
Les arguments standard contre l'optimisation prématurée s'appliquent, mais je ne pense pas que vous perdiez vraiment beaucoup de clarté / simplicité en utilisant re.compile
si vous pensez que vos expressions régulières peuvent devenir un goulot d'étranglement.
Voici un cas de test simple:
~$ for x in 1 10 100 1000 10000 100000 1000000; do python -m timeit -n $x -s 'import re' 're.match("[0-9]{3}-[0-9]{3}-[0-9]{4}", "123-123-1234")'; done
1 loops, best of 3: 3.1 usec per loop
10 loops, best of 3: 2.41 usec per loop
100 loops, best of 3: 2.24 usec per loop
1000 loops, best of 3: 2.21 usec per loop
10000 loops, best of 3: 2.23 usec per loop
100000 loops, best of 3: 2.24 usec per loop
1000000 loops, best of 3: 2.31 usec per loop
~$ for x in 1 10 100 1000 10000 100000 1000000; do python -m timeit -n $x -s 'import re; r = re.compile("[0-9]{3}-[0-9]{3}-[0-9]{4}")' 'r.match("123-123-1234")'; done
1 loops, best of 3: 1.91 usec per loop
10 loops, best of 3: 0.691 usec per loop
100 loops, best of 3: 0.701 usec per loop
1000 loops, best of 3: 0.684 usec per loop
10000 loops, best of 3: 0.682 usec per loop
100000 loops, best of 3: 0.694 usec per loop
1000000 loops, best of 3: 0.702 usec per loop
Donc, il semblerait que la compilation est plus rapide avec ce cas simple, même si vous ne correspondez qu'une seule fois .
J'ai juste essayé moi-même. Pour le cas simple de l'analyse d'un numéro à l'intérieur d'une chaîne et d'en résumé, à l'aide d'une expression régulière compilée objet est environ deux fois plus rapide que l'utilisation de l' re
méthodes.
Comme d'autres l'ont souligné, l' re
méthodes (y compris re.compile
) pour l'expression régulière dans une cache d'précédemment compilé expressions. Par conséquent, dans le cas normal, le coût supplémentaire de l'utilisation de l' re
méthodes est simplement le coût de la recherche dans le cache.
Toutefois, l'examen du code, montre que le cache est limité à 100 expressions. Cela soulève la question, à quel point est-il de débordement de la mémoire cache? Le code contient une interface interne à l'expression régulière compilateur, re.sre_compile.compile
. Si nous l'appelons, nous contourner le cache. Il s'avère à être d'environ deux ordres de grandeur plus lent pour une base de l'expression régulière, comme r'\w+\s+([0-9_]+)\s+\w*'
.
Voici mon test:
#!/usr/bin/env python importation re le délai d'importation def chronométré(func): def wrapper(*args): t = temps.temps (le) résultat = func(*args) t = temps.time() - t print '%s a duré %.3f secondes.' % (func.func_name, t) résultat de retour retour wrapper regularExpression = r'\w+\s+([0-9_]+)\s+\w*' chaîne de test = "moyenne 2 jamais" @chronométré def noncompiled(): a = 0 pour x in xrange(1000000): m = re.match(regularExpression, chaîne de test) a += int(m.groupe(1)) de retour d'un @chronométré def compilé(): a = 0 rgx = re.compiler(regularExpression) pour x in xrange(1000000): m = rgx.match(de test) a += int(m.groupe(1)) de retour d'un @chronométré def reallyCompiled(): a = 0 rgx = re.sre_compile.compiler(regularExpression) pour x in xrange(1000000): m = rgx.match(de test) a += int(m.groupe(1)) de retour d'un @chronométré def compiledInLoop(): a = 0 pour x in xrange(1000000): rgx = re.compiler(regularExpression) m = rgx.match(de test) a += int(m.groupe(1)) de retour d'un @chronométré def reallyCompiledInLoop(): a = 0 pour x in xrange(10000): rgx = re.sre_compile.compiler(regularExpression) m = rgx.match(de test) a += int(m.groupe(1)) de retour d'un r1 = noncompiled() r2 = compilé() r3 = reallyCompiled() r4 = compiledInLoop() r5 = reallyCompiledInLoop() print "r1 =" r1 print "r2 = ", r2 print "r3 = ", r3 print "r4 = ", r4 print "r5 = ", r5
Et voici le résultat sur ma machine:
$ regexTest.py noncompiled a pris 4.555 secondes. compilé pris 2.323 secondes. reallyCompiled a pris 2.325 secondes. compiledInLoop a pris 4.620 secondes. reallyCompiledInLoop a pris 4.074 secondes. r1 = 2000000 r2 = 2000000 r3 = 2000000 r4 = 2000000 r5 = 20000
Le " reallyCompiled des méthodes d'utilisation de l'interface interne, qui contourne le cache. Note celui qui compile sur chaque itération de boucle n'est répété 10 000 fois, pas un million.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.