2010-08-06 2 views
13

कहा जाता है यदि आप किसी फ़ंक्शन के अंदर रेगेक्स संकलित करते हैं, और उस फ़ंक्शन को कई बार कॉल किया जाता है, तो क्या पाइथन प्रत्येक बार रेगेक्स को फिर से कंपाइल करता है, या पाइथन संकलित रेगेक्स कैश करता है (रेगेक्स मानता है बदल नहीं है)?एक फ़ंक्शन के अंदर एक रेगेक्स संकलित करना जिसे कई बार

उदाहरण के लिए:

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.compile फ़ंक्शन कैश का उपयोग करता है जैसे कि अन्य सभी फ़ंक्शंस ऐसा करें, फिर एक ही रेगेक्स को बार-बार संकलित करना बहुत सस्ता है (एक शब्दकोश लुकअप)। दूसरे शब्दों में, कोड को सबसे समझने योग्य या रखरखाव या अभिव्यक्तिपूर्ण मानने के लिए लिखें, और रेगेक्स संकलन के ऊपरी हिस्से के बारे में चिंता न करें।

+0

आप सही हैं, [_compile फ़ंक्शन re.py] देखें (https://github.com/python/cpython/blob/master/Lib/re.py#L278) – pevik

0

यह "गलत" बात है, यहाँ विषय पर एक लंबे समय तक धागा है करता है।

I'm using Python regexes in a criminally inefficient manner

+1

दरअसल, वह लिंक आपको बताता है कि यह * सही * चीज करता है, लेकिन कैश की जांच के लिए गति दंड है। – katrielalex

6

आप re.compile हर बार बुला() की भूमि के ऊपर से बचना चाहते हैं, तो आप कर सकते हैं:

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

+1 मेरा शब्द, मैंने कभी नहीं सोचा था कि मुझे पाइथन का डिफ़ॉल्ट तर्क हैंडलिंग * उपयोगी * दिखाई देगा। – katrielalex

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

यह वही है जो मैं अब तक कर रहा हूं, लेकिन यह मुझे रेगेक्स को इसके उपयोग से दूर करने के लिए मजबूर करता है। –

2

डिंगो के समाधान के लिए एक अच्छा एक है [संपादित करें: नेड Batchelder के विवरण और भी बेहतर है], लेकिन यहाँ एक और एक है जो मुझे लगता है कि साफ है: उपयोग बंद! अगर यह आपके लिए "बड़ा शब्द" जैसा लगता है, तो चिंता न करें। अवधारणा सरल है:

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 केवल एक बार कहा जाता है, और इसलिए regex केवल एक बार संकलित किया गया है। फ़ंक्शन f, जिसे contains_text_of_interest पर असाइन किया गया है, संकलित रेगेक्स matcher के बारे में जानता है क्योंकि यह आसपास के दायरे में है, और यदि आप contains_text_of_interest कहीं और उपयोग करते हैं, तो यह हमेशा इसके बारे में पता होगा (यह बंद है: कोड जो इसके आसपास के दायरे को लेता है) ।

निश्चित रूप से इस समस्या का सबसे पाइथनिक समाधान नहीं है। लेकिन यह आपकी आस्तीन उठाने के लिए एक अच्छा मुहावरे है, क्योंकि जब समय सही है :)

संबंधित मुद्दे