12

Pythonドキュメントからre.compile()

注re.match()、re.search()、またはre.compile()に渡された最新のパターンのコンパイル済みバージョンはキャッシュされるため、一度に少数の正規表現のみを使用するプログラムは、正規表現のコンパイルについて心配する必要はありません。式。

しかし、私のテストでは、この主張は持ちこたえられていないようです。同じパターンを繰り返し使用する次のスニペットのタイミングをとる場合、コンパイルされたバージョンは、コンパイルされていないバージョン(おそらくキャッシュされているはずです)よりも大幅に高速です。

時差を説明する何かがここに欠けていますか?

import timeit

setup = """
import re
pattern = "p.a.t.t.e.r.n"
target = "p1a2t3t4e5r6n"
r = re.compile(pattern)
"""

print "compiled:", \
    min(timeit.Timer("r.search(target)", setup).repeat(3, 5000000))
print "uncompiled:", \
    min(timeit.Timer("re.search(pattern, target)", setup).repeat(3, 5000000))

結果:

compiled: 2.26673030059
uncompiled: 6.15612802627
4

1 に答える 1

13

の(CPython)実装は次の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.compile

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

依存するものre._compile

def _compile(*key):
    # internal: compile pattern
    cachekey = (type(key[0]),) + key
    p = _cache.get(cachekey)            #_cache is a dict.   
    if p is not None:
        return p
    pattern, flags = key
    if isinstance(pattern, _pattern_type):
        if flags:
            raise ValueError('Cannot process flags argument with a compiled pattern')
        return pattern 
    if not sre_compile.isstring(pattern):
        raise TypeError, "first argument must be string or compiled pattern"
    try:
        p = sre_compile.compile(pattern, flags)
    except error, v:
        raise error, v # invalid expression
    if len(_cache) >= _MAXCACHE:
        _cache.clear()
    _cache[cachekey] = p
    return p

したがって、正規表現が既に辞書にある限り、余分な作業は辞書の検索だけであることがわかります (これには、いくつかの一時的なタプルの作成、いくつかの追加の関数呼び出しが含まれます...)。

更新 古き良き時代 (上にコピーしたコード) では、キャッシュが大きくなりすぎると完全に無効化されていました。最近では、キャッシュ サイクルが繰り返され、最も古いアイテムが最初に削除されます。この実装は、python 辞書の順序付けに依存しています (これは、python3.7 までの実装の詳細でした)。python3.6 より前の Cpython では、これにより任意の値がキャッシュから削除されていました (これは、キャッシュ全体を無効にするよりも間違いなく優れています)。

于 2012-09-20T13:59:53.357 に答える