पायथन में, अगर मैं "ब्लॉक" के साथ वापस आता हूं, तो क्या फ़ाइल अभी भी बंद होगी?


256

निम्नलिखित को धयान मे रखते हुए:

with open(path, mode) as f:
    return [line for line in f if condition]

क्या फ़ाइल ठीक से बंद हो जाएगी, या returnकिसी भी तरह से संदर्भ प्रबंधक को बायपास कर देगा ?

जवाबों:


238

हां, यह finallyएक ब्लॉक के बाद ब्लॉक की तरह कार्य करता है try, अर्थात यह हमेशा निष्पादित होता है (जब तक कि अजगर प्रक्रिया असामान्य तरीके से समाप्त नहीं हो जाती)।

यह पीईपी -343 के उदाहरणों में से एक में भी वर्णित है जो कि विवरण के लिए विनिर्देश है with:

with locked(myLock):
    # Code here executes with myLock held.  The lock is
    # guaranteed to be released when the block is left (even
    # if via return or by an uncaught exception).

हालांकि, कुछ ध्यान देने योग्य बात यह है कि आप open()पूरे withब्लॉक को ब्लॉक के अंदर रखे बिना कॉल द्वारा फेंके गए अपवादों को आसानी से नहीं पकड़ सकते हैं, try..exceptजो आमतौर पर कोई भी नहीं चाहता है।


8
elsewithउस try with exceptसमस्या को हल करने के लिए जोड़ा जा सकता है। संपादित करें: भाषा में जोड़ा गया
rplnt

7
मुझे नहीं पता कि यह प्रासंगिक है, लेकिन मेरे ज्ञान Process.terminate()में से कुछ (एकमात्र) परिदृश्य में से एक है जो एक finallyबयान की कॉल की गारंटी नहीं देता है : "ध्यान दें कि बाहर निकलने वाले हैंडलर और अंत में क्लॉज़ इत्यादि नहीं होंगे। मार डाला। "
रीक पोगी

os._exitकभी-कभी @RikPoggi का उपयोग किया जाता है - यह सफाई संचालकों को बुलाए बिना पायथन प्रक्रिया से बाहर निकलता है।
एक्यूमेनस

2
शायद सांप को थोड़ा ताना दे, लेकिन क्या होगा अगर मैं withब्लॉक के भीतर से एक जनरेटर अभिव्यक्ति लौटाता हूं , तो जब तक जनरेटर मूल्यों को बनाए रखता है, तब तक क्या गारंटी है? जब तक कुछ भी इसे संदर्भित करता है? I क्या delजनरेटर ऑब्जेक्ट को रखने वाले वैरिएबल को एक अलग मूल्य का उपयोग या असाइन करने की आवश्यकता है ?
एक

1
@davidA फ़ाइल बंद होने के बाद, संदर्भ अभी भी सुलभ हैं; हालाँकि, डेटा को फ़ाइल से / खींचने के लिए संदर्भों का उपयोग करने का कोई भी प्रयास देगा ValueError: I/O operation on closed file.:।
RWDJ

36

हाँ।

def example(path, mode):
    with open(path, mode) as f:
        return [line for line in f if condition]

.. यह बहुत अधिक के बराबर है:

def example(path, mode):
    f = open(path, mode)

    try:
        return [line for line in f if condition]
    finally:
        f.close()

अधिक सटीक रूप से, __exit__एक संदर्भ प्रबंधक में विधि को हमेशा ब्लॉक से बाहर निकलते समय (अपवादों, रिटर्न आदि की परवाह किए बिना) कहा जाता है। फ़ाइल ऑब्जेक्ट का __exit__तरीका सिर्फ कॉल करता है f.close()(जैसे कि CPython में )


30
गारंटी आप से प्राप्त कर दिखाने के लिए एक दिलचस्प प्रयोग finallykeywrod है: def test(): try: return True; finally: return False
एहसान किआ

20

हाँ। आम तौर पर, __exit__एक संदर्भ कथन संदर्भ प्रबंधक की विधि को वास्तव returnमें संदर्भ के अंदर से घटना में कहा जाएगा । यह निम्नलिखित के साथ परीक्षण किया जा सकता है:

class MyResource:
    def __enter__(self):
        print('Entering context.')
        return self

    def __exit__(self, *exc):
        print('EXITING context.')

def fun():
    with MyResource():
        print('Returning inside with-statement.')
        return
    print('Returning outside with-statement.')

fun()

आउटपुट है:

Entering context.
Returning inside with-statement.
EXITING context.

उपरोक्त आउटपुट पुष्टि करता है कि __exit__शुरुआती के बावजूद बुलाया गया था return। जैसे, संदर्भ प्रबंधक को दरकिनार नहीं किया जाता है।


4

हां, लेकिन अन्य मामलों में कुछ दुष्प्रभाव हो सकते हैं, क्योंकि यह __exit__ब्लॉक में कुछ (जैसे फ्लशिंग बफर) करना चाहिए

import gzip
import io

def test(data):
    out = io.BytesIO()
    with gzip.GzipFile(fileobj=out, mode="wb") as f:
        f.write(data)
        return out.getvalue()

def test1(data):
    out = io.BytesIO()
    with gzip.GzipFile(fileobj=out, mode="wb") as f:
        f.write(data)
    return out.getvalue()

print(test(b"test"), test1(b"test"))

# b'\x1f\x8b\x08\x00\x95\x1b\xb3[\x02\xff' b'\x1f\x8b\x08\x00\x95\x1b\xb3[\x02\xff+I-.\x01\x00\x0c~\x7f\xd8\x04\x00\x00\x00'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.