2012-12-03 11 views
6

मैं कोड का यह स्निपेट मिल गया हैप्रसंस्करण केवल गैर रिक्त लाइनों

def send(self, queue, fd): 
    for line in fd: 
     data = line.strip() 
     if data: 
      queue.write(json.loads(data)) 

निश्चित रूप से कौन सा बस ठीक काम करता है, लेकिन मैं कभी कभी आश्चर्य है कि अगर वहाँ एक "बेहतर" तरीका है कि निर्माण में लिखने के लिए जहां केवल गैर-खाली लाइनों पर कार्य करें।

चुनौती यह है कि इसे 'एफडी' पढ़ने के लिए पुनरावृत्ति प्रकृति का उपयोग करना चाहिए और 100+ एमबी रेंज में फ़ाइलों को संभालने में सक्षम होना चाहिए।

अद्यतन - इस प्रश्न के लिए अंक प्राप्त करने के लिए अपने जल्दबाजी में आप एक आयात भाग को अनदेखा कर रहे हैं, जो स्मृति उपयोग है। उदाहरण अभिव्यक्ति के लिए:

non_blank_lines = (line.strip() for line in fd if line.strip()) 

स्मृति में पूरी फ़ाइल बफ़र होना, नहीं एक पट्टी() कार्रवाई दो बार प्रदर्शन का उल्लेख करने के लिए जा रहा है। जो छोटी फाइलों के लिए काम करेगा, लेकिन जब आपके पास 100 + एमबी डेटा (या एक बार 100 जीबी में) हो तो विफल हो जाता है।

चुनौती का एक हिस्सा निम्नलिखित काम करता है, लेकिन पढ़ने के लिए सूप है: जादू लोगों के लिए

for line in ifilter(lambda l: l, imap(lambda l: l.strip(), fd)): 
    queue.write(json.loads(line)) 

देखो!

अंतिम अद्यतन: PEP-289 [] और() के बीच अंतर की अपनी बेहतर समझ के लिए बहुत उपयोगी है।

+0

यह आपके प्रश्न का बिल्कुल जवाब नहीं है, लेकिन बड़ी फ़ाइलों के लिए, आप IO (http://neopythonic.blogspot.com/2008/10/sorting-million-32-bit buffered करने के लिए एक नज़र डालना चाहते हैं -इंटरर्स-इन -2mb.html) – BorrajaX

+1

मैं वास्तव में एक बेहतर तरीके से नहीं सोच सकता। केवल एक चीज जो आप कर सकते हैं वह आपके 'fd' ऑब्जेक्ट के लिए अपना' __iter__' फ़ंक्शन लिखना है (जिसे आपने हमें अधिक जानकारी नहीं दी है) ताकि वह केवल आपकी उबाऊ हो जो खाली नहीं हो। – jdotjdot

+0

एफडी बहुत आसान है: '' खुला (FILENAME) के साथ fd: '' – koblas

उत्तर

4

लिखित कोड के साथ कुछ भी गलत नहीं है, यह पठनीय और कुशल है।

def send(self, queue, fd): 
    non_blank_lines = (line.strip() for line in fd if line.strip()) 
    for line in non_blank_lines: 
     queue.write(json.loads(data)) 

यह दृष्टिकोण लाभकारी (terser) हो सकता है अगर आप एक समारोह है कि एक इटरेटर ले जा सकते हैं आवेदन कर रहे हैं:

एक वैकल्पिक दृष्टिकोण एक जनरेटर समझ के रूप में यह लिखने के लिए होगा जैसे python3

non_blank_lines = (line.strip() for line in fd if line.strip()) 
print(*non_blank_lines, file='foo') 

कई कॉल के साथ भाग करने के लिए पट्टी (प्रिंट), श्रृंखला एक साथ जनरेटर comprehensions

stripped_lines = (line.strip() for line in fd) 
non_blank_lines = (line for line in stripped_lines if line) 

नोट के रूप में इस pep में विस्तृत है कि जनरेटर भाव पर प्रतिकूल स्मृति को प्रभावित नहीं करेगा।

इस दृष्टिकोण पर गहराई से देखने के लिए, और कुछ प्रदर्शन बेंच अंक, notes के इस सेट पर एक नज़र डालें।

अंत में ध्यान दें कि अगर आपको स्ट्रिप() के पूर्ण व्यवहार की आवश्यकता नहीं है तो rstrip() स्ट्रिप() को बेहतर प्रदर्शन करेगा।

+0

आपके द्वारा उद्धृत पीईपी बहुत मूल्यवान है। – koblas

1

आपके मुकाबले कोई "बेहतर" तरीका नहीं है, यह जिस तरह से माना जाता है, यह पढ़ना आसान है, आदि। हालांकि, अगर आप गति को "बेहतर" वर्गीकृत करते हैं, तो निश्चित रूप से छोटे समायोजन किए जा सकते हैं।

मैंने पाइथन पर इस गति सामग्री के साथ खुद को बहुत परिचित नहीं किया है, लेकिन यहां कुछ सुझाव दिए गए हैं, जो केवल कुछ शर्तों के तहत काम करते हैं। मुझे आशा है कि कोई और कुछ बेहतर तरीके से आएगा, शायद यह जवाब उनकी मदद करेगा।

फ़ाइल ऐसे

 \n 

लेकिन इसके बजाय केवल \n के रूप में लाइनों को शामिल नहीं जाएगा, तो इस तरह से काफ़ी तेजी से हो जाएगा:

def send(self, queue, fd): 
    for line in fd: 
     if line != '\n': 
      queue.write(json.loads(line.strip())) 

Timeit मान:

using: strip() :: 1.8722578811916337 
using: line != '\n' :: 1.0126976271093881 
using: line != '\n' and line != ' \n' :: 1.2862439244170275 

नोटिस हालांकि, यह वास्तव में धीमा हो सकता है, अगर फ़ाइल में एक भी एल नहीं है \n की ऑफ़लाइन, मैं इसे fd जा रहा है ["string", "\n", "test string", "\n", "moreeee", "\n", "An other element"]

लाइनें हैं अगर \n केवल, तथापि, .strip() काफी धीमी है जैसा कि आप जानते नहीं है के साथ समय समाप्त हो गया है, इसलिए अधिक बेहतर तरीके हो सकते हैं।

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