2010-08-06 60 views
13

如果在函数内部编译正则表达式,并且该函数被多次调用,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 

回答

11

实际上,如果你看看re模块中的代码,re.compile函数就像所有其他函数一样使用缓存这样做,所以一遍又一遍地编译相同的正则表达式非常便宜(字典查找)。换句话说,编写代码是最容易理解或可维护或表达的,并且不用担心编译正则表达式的开销。

+0

你是对的,请参阅[re.py中的_compile函数](https://github.com/python/cpython/blob/master/Lib/re.py#L278) – pevik 2016-03-30 08:33:49

6

如果你想避免调用re.compile()每一次的开销,你可以这样做:

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

+1我的话,我从来没有想过我会看到Python的默认参数处理是*有用*。 – katrielalex 2010-08-06 21:23:56

2

你为什么不干脆把re.compile功能外(在模块或类级别),给它一个明确的名称,并使用它?这种正则表达式是一种常量,你可以用同样的方式来对待它。

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

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

这就是我迄今为止所做的,但是这迫使我定义远离它的使用的正则表达式比我想要的更远。 – 2010-08-07 11:49:28

2

巴丁格的解决方案是一个很好的[编辑:斯内德尔德的解释是更好],但这里有另外一个我认为是整齐的:使用闭!如果这听起来像是一个“大词汇”,不要担心。这个概念很简单:

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只调用一次,因此正则表达式编译只有一次。编号为contains_text_of_interest的函数f知道编译后的正则表达式matcher,因为它位于周围的范围内,并且始终知道它,即使在其他位置使用contains_text_of_interest(即,闭包:将周围范围与它一起使用的代码) 。

当然,这不是对这个问题的最Pythonic解决方案。但是,这是一个很好的习惯用法,因为时间是正确的:)