मुझे पायथन में एक फाइल लाइन-बाय-लाइन कैसे पढ़नी चाहिए?


137

पूर्व-ऐतिहासिक समय में (अजगर 1.4) हमने किया था:

fp = open('filename.txt')
while 1:
    line = fp.readline()
    if not line:
        break
    print line

पायथन 2.1 के बाद, हमने किया:

for line in open('filename.txt').xreadlines():
    print line

इससे पहले कि हम पायथन 2.3 में सुविधाजनक पुनरावृत्ति प्रोटोकॉल प्राप्त कर सकें, और कर सकें:

for line in open('filename.txt'):
    print line

मैंने अधिक क्रिया का उपयोग करके कुछ उदाहरण देखे हैं:

with open('filename.txt') as fp:
    for line in fp:
        print line

क्या यह पसंदीदा तरीका आगे बढ़ रहा है?

[संपादित करें] मुझे लगता है कि बयान के साथ फ़ाइल को बंद करना सुनिश्चित करता है ... लेकिन फ़ाइल ऑब्जेक्ट के लिए पुनरावृत्ति प्रोटोकॉल में इसे शामिल क्यों नहीं किया गया है?


4
imho, आखिरी सुझाव पहले की तुलना में अधिक क्रिया नहीं है। यह सिर्फ और अधिक काम करता है (यह सुनिश्चित करता है कि आपके काम करने के दौरान फ़ाइल बंद हो जाती है)।
अज़रेई

1
@azhrei यह एक पंक्ति अधिक है, इसलिए वास्तव में यह अधिक क्रिया है।
Thebjorn

7
मुझे वह मिलता है जो आप कह रहे हैं, लेकिन मैं सिर्फ सेब के साथ सेब की तुलना कर रहा हूं, आपकी पोस्ट के दूसरे आखिरी सुझाव को अपवाद हैंडलिंग कोड के साथ-साथ अंतिम विकल्प से मिलान करने की आवश्यकता है। तो व्यवहार में यह अधिक क्रिया है। मुझे लगता है कि यह संदर्भ पर निर्भर करता है कि पिछले दो विकल्पों में से कौन सा सबसे अच्छा है, वास्तव में।
अज़रेई

जवाबों:


227

निम्नलिखित को प्राथमिकता देने का एक कारण है:

with open('filename.txt') as fp:
    for line in fp:
        print line

कचरा संग्रहण के लिए सीपीथॉन की अपेक्षाकृत निर्धारक संदर्भ-गिनती योजना से हम सभी खराब हो गए हैं। अन्य, पायथन के काल्पनिक कार्यान्वयन आवश्यक रूप से withब्लॉक के बिना "जल्दी से पर्याप्त" फ़ाइल को बंद नहीं करेंगे यदि वे स्मृति को पुनः प्राप्त करने के लिए किसी अन्य योजना का उपयोग करते हैं।

इस तरह के कार्यान्वयन में, आपको ओएस से "बहुत सारी फाइलें खुली" त्रुटि मिल सकती है यदि आपका कोड कचरा संग्रहकर्ता से अनाथ फ़ाइल हैंडल पर कॉलर्स को अंतिम रूप से तेजी से फाइल खोलता है। सामान्य वर्कअराउंड जीसी को तुरंत ट्रिगर करना है, लेकिन यह एक बुरा हैक है और इसे प्रत्येक फ़ंक्शन द्वारा किया जाना चाहिए जो त्रुटि का सामना कर सकता है, जिसमें पुस्तकालय भी शामिल हैं। कितना बुरा सपना।

या आप withब्लॉक का उपयोग कर सकते हैं ।

बोनस प्रश्न

(अब पढ़ना बंद कर दें यदि केवल सवाल के उद्देश्य पहलुओं में रुचि रखते हैं।)

फ़ाइल ऑब्जेक्ट के लिए पुनरावृत्ति प्रोटोकॉल में इसे शामिल क्यों नहीं किया गया है?

यह एपीआई डिजाइन के बारे में एक व्यक्तिपरक प्रश्न है, इसलिए मेरे पास दो भागों में एक व्यक्तिपरक उत्तर है।

एक आंत स्तर पर, यह गलत लगता है, क्योंकि यह इटरेटर प्रोटोकॉल दो अलग-अलग काम करता है - लाइनों पर पुनरावृति और फ़ाइल हैंडल को बंद करना - और यह अक्सर एक साधारण दिखने वाले फ़ंक्शन को दो क्रियाएं करने के लिए एक बुरा विचार है। इस मामले में, यह विशेष रूप से बुरा लगता है क्योंकि पुनरावृत्त एक फ़ाइल की सामग्री के लिए एक अर्ध-कार्यात्मक, मूल्य-आधारित तरीके से संबंधित हैं, लेकिन फ़ाइल हैंडल का प्रबंधन एक पूरी तरह से अलग कार्य है। दोनों को स्क्वीज़ करना, अदृश्य रूप से, एक क्रिया में, उन मनुष्यों के लिए आश्चर्यजनक है जो कोड पढ़ते हैं और प्रोग्राम व्यवहार के बारे में तर्क करना अधिक कठिन बना देते हैं।

अन्य भाषाएँ अनिवार्य रूप से उसी निष्कर्ष पर पहुँची हैं। हास्केल ने तथाकथित "आलसी IO" के साथ संक्षेप में छेड़खानी की, जो आपको एक फ़ाइल पर पुनरावृत्त करने की अनुमति देता है और धारा के अंत में आने पर स्वचालित रूप से बंद हो जाता है, लेकिन यह इन दिनों हास्केल में आलसी आईओ का उपयोग करने के लिए लगभग सार्वभौमिक रूप से हतोत्साहित है, और हास्केल उपयोगकर्ता ज्यादातर कोंडिट जैसे अधिक स्पष्ट संसाधन प्रबंधन में चले गए हैं जो withपायथन में ब्लॉक की तरह अधिक व्यवहार करता है ।

तकनीकी स्तर पर, कुछ चीजें हैं जो आप पायथन में एक फ़ाइल हैंडल के साथ करना चाह सकते हैं जो कि फ़ाइल हैंडल को बंद करने पर भी काम नहीं करेगा। उदाहरण के लिए, मान लें कि मुझे फ़ाइल पर दो बार पुनरावृति करने की आवश्यकता है:

with open('filename.txt') as fp:
    for line in fp:
        ...
    fp.seek(0)
    for line in fp:
        ...

हालांकि यह एक कम सामान्य उपयोग का मामला है, इस तथ्य पर विचार करें कि मैंने कोड की तीन पंक्तियों को एक मौजूदा कोड बेस में सबसे नीचे जोड़ा होगा, जिसमें मूल रूप से शीर्ष तीन लाइनें थीं। यदि पुनरावृति ने फ़ाइल को बंद कर दिया, तो मैं ऐसा नहीं कर पाऊंगा। तो पुनरावृत्ति और संसाधन प्रबंधन को अलग रखने से कोड के विखंडू को एक बड़े, काम कर रहे पायथन कार्यक्रम में रचना करना आसान हो जाता है।

संगतता भाषा या एपीआई की सबसे महत्वपूर्ण प्रयोज्यता सुविधाओं में से एक है।


1
+1 क्योंकि यह op पर मेरी टिप्पणी में "जब" की व्याख्या करता है ;-)
azhrei

वैकल्पिक कार्यान्वयन के साथ, हैंडलर के साथ केवल उन कार्यक्रमों के लिए समस्याएँ पैदा करने जा रहे हैं जो बहुत जल्दी उत्तराधिकार में सैकड़ों फाइलें खोलते हैं। अधिकांश प्रोग्राम बिना किसी समस्या के झूलते हुए फ़ाइल संदर्भ के साथ प्राप्त कर सकते हैं। जब तक आप इसे अक्षम नहीं करते, अंततः जीसी कुछ समय में किक करेगा और फ़ाइल हैंडल को साफ़ करेगा। withहालांकि आपको मन की शांति मिलती है, इसलिए यह अभी भी एक सर्वोत्तम अभ्यास है।
रेयान

1
@DietrichEpp: शायद "डैंगलिंग फाइल रेफरेंस" सही शब्द नहीं थे, मेरा वास्तव में फाइल हैंडल था जो अब सुलभ नहीं था लेकिन अभी तक बंद नहीं हुआ है। किसी भी स्थिति में, फ़ाइल ऑब्जेक्ट को इकट्ठा करने पर GC फ़ाइल हैंडल को बंद कर देगा, इसलिए जब तक आपके पास फ़ाइल ऑब्जेक्ट के अतिरिक्त संदर्भ नहीं होते हैं और आप GC को अक्षम नहीं करते हैं और आप त्वरित रूप से कई फ़ाइलों को नहीं खोल रहे हैं। उत्तराधिकार, आपको फ़ाइल बंद न करने के कारण "बहुत अधिक फाइलें खुली" होने की संभावना नहीं है।
रेयान

1
हां, इसका ठीक यही अर्थ है कि "यदि आपका कोड कचरा संग्रहकर्ता द्वारा अनाथ फ़ाइल हैंडल पर अंतिम रूप से कॉल करने वालों की तुलना में तेजी से फाइल खोलता है"।
डिट्रिच एप ईप

1
के साथ उपयोग करने का बड़ा कारण यह है कि यदि आप फ़ाइल को बंद नहीं करते हैं, तो यह जरूरी नहीं कि तुरंत लिखा जाए।
एंटीमनी

20

हाँ,

with open('filename.txt') as fp:
    for line in fp:
        print line

जाने का रास्ता है।

यह अधिक क्रिया नहीं है। यह अधिक सुरक्षित है।


5

यदि आप अतिरिक्त लाइन से बंद हो गए हैं, तो आप एक रैपर फ़ंक्शन का उपयोग कर सकते हैं:

def with_iter(iterable):
    with iterable as iter:
        for item in iter:
            yield item

for line in with_iter(open('...')):
    ...

पायथन 3.3 में, यह yield fromकथन इसे और भी छोटा बना देगा:

def with_iter(iterable):
    with iterable as iter:
        yield from iter

2
फ़ंक्शन xreadlines को कॉल करें .. और इसे xreadlines.py नामक फ़ाइल में रखें और हम Python 2.1 सिंटैक्स पर वापस
आएँ

@thebjorn: शायद, लेकिन आपके द्वारा उद्धृत किए गए पायथन 2.1 उदाहरण वैकल्पिक कार्यान्वयन में मौजूद फ़ाइल हैंडलर से सुरक्षित नहीं थे। एक पायथन 2.1 फाइल रीडिंग जो कि बिना फाइल किए हैंडलर से सुरक्षित है, कम से कम 5 लाइनें लेगा।
रेयान

-1
f = open('test.txt','r')
for line in f.xreadlines():
    print line
f.close()

5
यह वास्तव में इस सवाल का जवाब नहीं देता है
Thayne
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.