পাইথনে, আমি যদি একটি "উইথ" ব্লকের ভিতরে ফিরে যাই, ফাইলটি কি এখনও বন্ধ হবে?


256

নিম্নোক্ত বিবেচনা কর:

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

ফাইলটি কি ঠিকঠাকভাবে বন্ধ হয়ে যাবে, বা প্রসঙ্গ পরিচালককেreturn কোনওভাবে বাইপাস ব্যবহার করে ?

উত্তর:


238

হ্যাঁ, এটি finallyএকটি ব্লকের পরে ব্লকের মতো কাজ করে try, যেমন এটি সর্বদা চালিত হয় (যদি না অজগর প্রক্রিয়াটি একটি অস্বাভাবিক পদ্ধতিতে শেষ হয়)।

এটি PEP-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মাঝে মাঝে ব্যবহৃত হয় - এটি ক্লিনআপ হ্যান্ডলারদের কল না করে পাইথন প্রক্রিয়াটি থেকে বেরিয়ে যায়।
একিউম্যানাস

2
সম্ভবত সাপটিকে কিছুটা গালি দেওয়া, তবে আমি যদি withব্লকের মধ্যে থেকে কোনও জেনারেটর এক্সপ্রেশন ফিরে পাই তবে জেনারেটর যতক্ষণ ধরে মান দেয় না তার গ্যারান্টিটি কী ধরে রাখতে পারে? কোন কিছুর জন্য এটি রেফারেন্স হিসাবে? অর্থাৎ delজেনারেটর অবজেক্টটি ধারণ করে এমন ভেরিয়েবলের জন্য আমার কি আলাদা মান ব্যবহার বা নির্ধারণ করা দরকার ?
ack

1
@ ডেভিডা ফাইলটি বন্ধ হওয়ার পরে, তথ্যসূত্রগুলি এখনও অ্যাক্সেসযোগ্য; তবে কোন করার জন্য প্রচেষ্টার সংখ্যা ব্যবহার ফাইল থেকে / টানুন / ধাক্কা ডেটাতে রেফারেন্স দিতে হবে: 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()(যেমন সিপিথনে এখানে )


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'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.