পাইথন 'উইথ' স্টেটমেন্ট ব্যবহার করার সময় একটি ব্যতিক্রম ধরা


293

আমার লজ্জার বিষয়, আমি কীভাবে পাইথন 'উইথ' স্টেটমেন্টের ব্যতিক্রম হ্যান্ডেল করব তা বুঝতে পারি না। আমার যদি একটি কোড থাকে:

with open("a.txt") as f:
    print f.readlines()

কিছু করার জন্য আমি সত্যিই 'ফাইলটি ব্যতিক্রম পাইনি' হ্যান্ডেল করতে চাই। তবে আমি লিখতে পারি না

with open("a.txt") as f:
    print f.readlines()
except:
    print 'oops'

এবং লিখতে পারে না

with open("a.txt") as f:
    print f.readlines()
else:
    print 'oops'

'চেষ্টা' করে 'বরাবর' বদ্ধ হওয়া / বিবৃতি ব্যতীত অন্য কোনও কাজ করে না: ব্যতিক্রম উত্থাপিত হয় না। পাইথোনিক উপায়ে 'উইথ' স্টেটমেন্টের ভিতরে ব্যর্থতা প্রক্রিয়া করতে আমি কী করতে পারি?


" কীভাবে " চেষ্টা করে "বেষ্টন করা" বা বিবৃতি ব্যতীত অন্য কোনও কাজ করে না: ব্যতিক্রম উত্থাপিত হয় না তার অর্থ কী? একটি withবিবৃতি ম্যাজিকভাবে পার্শ্ববর্তী try...exceptবিবৃতি ভঙ্গ করে না ।
অরণ-ফে

4
মজার বিষয় হল, জাভার চেষ্টা সহ-সংস্থান বিবরণী আপনি চান ঠিক এই ব্যবহারের ক্ষেত্রে সমর্থন করেdocs.oracle.com/javase/tutorial/essential/exception/…
নায়ুকি

উত্তর:


256
from __future__ import with_statement

try:
    with open( "a.txt" ) as f :
        print f.readlines()
except EnvironmentError: # parent of IOError, OSError *and* WindowsError where available
    print 'oops'

যদি আপনি ওপেন কল বনাম ওয়ার্কিং কোড থেকে ত্রুটিগুলির জন্য বিভিন্ন পরিচালনা করতে চান তবে আপনি করতে পারেন:

try:
    f = open('foo.txt')
except IOError:
    print('error')
else:
    with f:
        print f.readlines()

3
স্ট্যাকওভারফ্লো / প্রশ্ন / 5205811/… তে উল্লিখিত হিসাবে , এখানে চেষ্টা ব্লকটি আসলেই খুব বিস্তৃত। কনটেক্সট ম্যানেজার তৈরি করার সময় এবং বিবৃতিতে যার মূল শৃঙ্খলে রয়েছে তার ব্যতিক্রমগুলির মধ্যে কোনও পার্থক্য তৈরি হয় না, সুতরাং এটি সমস্ত ব্যবহারের ক্ষেত্রে বৈধ সমাধান নাও হতে পারে।
এনকোঘ্লান

@ncoghlan তবে কোনও ব্যতিক্রমের উত্সের সান্নিধ্য পেতে আপনি try...exceptভিতরে অতিরিক্ত ব্লক যুক্ত withকরতে পারেন যার কিছু করার নেই open()
rbaleksandar

1
@ আরবালেকসান্দার যদি আমি সঠিকভাবে স্মরণ করি তবে আমার মন্তব্যটি উত্তরের প্রথম উদাহরণটিকে কঠোরভাবে উল্লেখ করছে, যেখানে বিবৃতি সহ পুরোটি চেষ্টা / ব্লক ব্যতীত রয়েছে (সুতরাং আপনার অভ্যন্তরীণ চেষ্টা থাকলেও / ব্লকগুলি প্রত্যাশা করলেও কোনও ব্যতিক্রম তারা পালাতে দেবে তবুও বাইরেরটিকে আঘাত করুন)। ডগলাস পরবর্তী ক্ষেত্রে সেই বিধানের বিষয়টি বিবেচনা করার জন্য দ্বিতীয় উদাহরণ যুক্ত করেছিলেন।
ncoghlan

3
এই উদাহরণে ফাইলটি বন্ধ হয়ে যাবে? আমি জিজ্ঞাসা করি কারণ এটি "সহ" সুযোগের বাইরে খোলা হয়েছিল।
মাইক কলিন্স

6
@ মাইককোলিনস 'উইথ' এর সাথে প্রস্থান করলে ফাইলটি 'উইথ' এর আগে খোলা থাকলেও বন্ধ হয়ে যাবে।
user7938784

75

এটি করার সর্বোত্তম "পাইথোনিক" উপায়টি withবিবৃতিটি কাজে লাগিয়ে পিইপি 343-তে উদাহরণ # 6 হিসাবে তালিকাভুক্ত হয়েছে যা বিবৃতিটির পটভূমি দেয়।

@contextmanager
def opened_w_error(filename, mode="r"):
    try:
        f = open(filename, mode)
    except IOError, err:
        yield None, err
    else:
        try:
            yield f, None
        finally:
            f.close()

নিম্নলিখিত হিসাবে ব্যবহৃত:

with opened_w_error("/etc/passwd", "a") as (f, err):
    if err:
        print "IOError:", err
    else:
        f.write("guido::0:0::/:/bin/sh\n")

38
আমি এটি পছন্দ করি তবে এটি কিছুটা বেশি কালো যাদু বলে মনে হয়। এটি সম্পূর্ণরূপে পাঠকের পক্ষে সুস্পষ্ট নয়
পল সীব

5
@ পলসীবি আপনি কেন এটি সংজ্ঞায়িত করবেন না এবং প্রতিবার আপনার যা প্রয়োজন তা করা থেকে নিজেকে বাঁচবেন না? এটি আপনার অ্যাপ্লিকেশন পর্যায়ে সংজ্ঞায়িত হয়েছে, এবং এটি অন্য কোনও প্রসঙ্গের মতো ম্যাজিক। আমি মনে করি সাথে বিবৃতিটি ব্যবহার করে কেউ এটি স্পষ্টভাবে বুঝতে পারে (ফাংশনটির নামটি যদি আপনি এটি পছন্দ না করেন তবে এটি আরও উদ্বেগজনক হতে পারে)। "উইথ" স্টেটমেন্টটি নিজেই এইভাবে কাজ করতে ইঞ্জিনিয়ার করা হয়েছে, কোডের একটি "সুরক্ষিত" ব্লক সংজ্ঞায়িত করতে এবং প্রসঙ্গ পরিচালকদের (কোডটি আরও স্পষ্ট করার জন্য) পরীক্ষা করার ফাংশনগুলি অর্পণ করতে।

9
এই সমস্ত সমস্যাটি কেবলমাত্র ইউজার কোডে অবশেষে ব্লক না লিখে। আমি ভাবতে শুরু করেছি যে আমরা সবাই বিবৃতি সহ একটি দীর্ঘ হাইপ লক্ষণের জন্য ভুগছি।
jgomo3

1
পাইথনে ব্যতিক্রমগুলি হ্যান্ডেল করার সর্বোত্তম উপায় হ'ল কোনও ফাংশন লিখুন যা তাদের ধরে ফেলে এবং ফিরে আসে? সিরিয়াসলি? ব্যতিক্রমগুলি পরিচালনা করার অজগর উপায়টি হল একটি try...exceptবিবৃতি ব্যবহার করা ।
অরণ-ফে

58

পাইথন 'উইথ' স্টেটমেন্ট ব্যবহার করার সময় একটি ব্যতিক্রম ধরা

পাইথন ২.6 থেকে__future__ আমদানি ছাড়াই স্টেটমেন্ট সহ উপলব্ধ রয়েছে । আপনি পাইথন 2.5 এর প্রথম দিকে এটি পেতে পারেন (তবে এই মুহুর্তে এটি আপগ্রেড হওয়ার সময়!) সহ:

from __future__ import with_statement

আপনার কাছে যা সংশোধন করা হয়েছে এটি নিকটতম জিনিস। আপনি প্রায় সেখানে আছেন, তবে এর withএকটি exceptধারা নেই:

with open("a.txt") as f: 
    print(f.readlines())
except:                    # <- with doesn't have an except clause.
    print('oops')

একটি প্রসঙ্গে পরিচালকের __exit__পদ্ধতি, যদি এটি ফিরে আসে Falseতবে শেষ হয়ে গেলে ত্রুটিটিকে পুনরায় সাজিয়ে তুলবে। যদি এটি ফিরে আসে তবে এটি Trueদমন করবে। openBuiltin এর __exit__ফেরত দেয় না True, তাই আপনি শুধু একটি ব্যবহার করে দেখুন এটা নীড় প্রয়োজন, ব্লক ছাড়া:

try:
    with open("a.txt") as f:
        print(f.readlines())
except Exception as error: 
    print('oops')

এবং স্ট্যান্ডার্ড বয়লারপ্লেট: একটি খালি ব্যবহার করবেন না except:যা ক্যাচ BaseExceptionকরে এবং অন্য সমস্ত সম্ভাব্য ব্যতিক্রম এবং সতর্কতা। কমপক্ষে হিসাবে নির্দিষ্ট হতে হবে Exceptionএবং এই ত্রুটির জন্য, সম্ভবত ধরা IOError। কেবলমাত্র ত্রুটিগুলি ধরুন যা আপনি পরিচালনা করতে প্রস্তুত।

সুতরাং এই ক্ষেত্রে, আপনি কি করতে চাই:

>>> try:
...     with open("a.txt") as f:
...         print(f.readlines())
... except IOError as error: 
...     print('oops')
... 
oops

2

যৌগিক withবিবৃতি থেকে উত্থাপিত ব্যতিক্রমগুলির সম্ভাব্য উত্সের মধ্যে পার্থক্য

একটি withবিবৃতিতে ঘটে যাওয়া ব্যতিক্রমগুলির মধ্যে পার্থক্য করা জটিল কারণ তারা বিভিন্ন জায়গায় উত্পন্ন হতে পারে। নিম্নলিখিত স্থানগুলির (বা সেখানে ফাংশনগুলি বলা হয়) থেকে ব্যতিক্রমগুলি উত্থাপিত হতে পারে:

  • ContextManager.__init__
  • ContextManager.__enter__
  • শরীর with
  • ContextManager.__exit__

আরও তথ্যের জন্য কনটেক্সট ম্যানেজার প্রকার সম্পর্কে ডকুমেন্টেশন দেখুন ।

আমরা শুধু মোড়কে এই বিভিন্ন ক্ষেত্রে মধ্যে পার্থক্য করতে চান তাহলে, withএকটি মধ্যে try .. exceptযথেষ্ট নয়। নিম্নলিখিত উদাহরণটি বিবেচনা করুন (উদাহরণ ValueErrorহিসাবে ব্যবহার করে তবে অবশ্যই এটি অন্য কোনও ব্যতিক্রম প্রকারের সাথে প্রতিস্থাপন করা যেতে পারে):

try:
    with ContextManager():
        BLOCK
except ValueError as err:
    print(err)

এখানে exceptচারটি পৃথক পৃথক জায়গাতেই উদ্ভূত ব্যতিক্রমগুলি ধরবে এবং এইভাবে তাদের মধ্যে পার্থক্য করতে দেয় না। আমরা বাইরে প্রসঙ্গ ম্যানেজার বস্তুর ইনস্ট্যান্স সরালে with, আমরা মধ্যে প্রভেদ করতে পারে __init__এবং BLOCK / __enter__ / __exit__:

try:
    mgr = ContextManager()
except ValueError as err:
    print('__init__ raised:', err)
else:
    try:
        with mgr:
            try:
                BLOCK
            except TypeError:  # catching another type (which we want to handle here)
                pass
    except ValueError as err:
        # At this point we still cannot distinguish between exceptions raised from
        # __enter__, BLOCK, __exit__ (also BLOCK since we didn't catch ValueError in the body)
        pass

কার্যকরভাবে এটি কেবল __init__অংশটির সাথে সহায়তা করেছে তবে আমরা withশুরুর শরীরটি কার্যকর করতে শুরু করেছে (অর্থাত্ __enter__অন্যের মধ্যে পার্থক্য করা ) কিনা তা পরীক্ষা করতে একটি অতিরিক্ত সেন্ডিনেল ভেরিয়েবল যুক্ত করতে পারি :

try:
    mgr = ContextManager()  # __init__ could raise
except ValueError as err:
    print('__init__ raised:', err)
else:
    try:
        entered_body = False
        with mgr:
            entered_body = True  # __enter__ did not raise at this point
            try:
                BLOCK
            except TypeError:  # catching another type (which we want to handle here)
                pass
    except ValueError as err:
        if not entered_body:
            print('__enter__ raised:', err)
        else:
            # At this point we know the exception came either from BLOCK or from __exit__
            pass

জটিল অংশটি হ'ল ব্যতিক্রম থেকে উদ্ভূত ব্যতিক্রমগুলির মধ্যে পার্থক্য করা BLOCKএবং __exit__কারণ একটি ব্যতিক্রম যা দেহের হাত থেকে রক্ষা পেয়েছে withতা পাস করা হবে __exit__যা কীভাবে এটি পরিচালনা করতে পারে তা সিদ্ধান্ত নিতে পারে ( দস্তাবেজগুলি দেখুন )। তবে যদি __exit__নিজেকে উত্থাপন করে তবে মূল ব্যতিক্রমটি নতুন দ্বারা প্রতিস্থাপন করা হবে। এই কেসগুলি মোকাবেলা করার জন্য আমরা কোনও সম্ভাব্য ব্যতিক্রম যা অন্যথায় নজরে না গিয়ে পালাতে পারত এবং পরবর্তী সময়ে বাইরের দিকে ধরা পড়ে থাকা ব্যক্তির সাথে এটির তুলনা করতে পারে এমন কোনও সম্ভাব্য ব্যতিক্রম সংরক্ষণ করার জন্য আমরা সাধারণ exceptশৃঙ্খলা যুক্ত করতে পারি - যদি সেগুলি একই হয় তবে এর অর্থ হ'ল উত্সটি ছিল বা অন্যথায় এটি ছিল (ক্ষেত্রে যদি সত্যতম মানটি বহিরাগতকে ফেরত দিয়ে ব্যতিক্রমকে দমন করেwithexceptBLOCK__exit____exit__except খালি কার্যকর করা হবে না)।

try:
    mgr = ContextManager()  # __init__ could raise
except ValueError as err:
    print('__init__ raised:', err)
else:
    entered_body = exc_escaped_from_body = False
    try:
        with mgr:
            entered_body = True  # __enter__ did not raise at this point
            try:
                BLOCK
            except TypeError:  # catching another type (which we want to handle here)
                pass
            except Exception as err:  # this exception would normally escape without notice
                # we store this exception to check in the outer `except` clause
                # whether it is the same (otherwise it comes from __exit__)
                exc_escaped_from_body = err
                raise  # re-raise since we didn't intend to handle it, just needed to store it
    except ValueError as err:
        if not entered_body:
            print('__enter__ raised:', err)
        elif err is exc_escaped_from_body:
            print('BLOCK raised:', err)
        else:
            print('__exit__ raised:', err)

পিইপি 343 এ উল্লিখিত সমতুল্য ফর্মটি ব্যবহার করে বিকল্প পদ্ধতি

পিইপি 343 - "উইথ" স্টেটমেন্ট বিবৃতিটির সমতুল্য "অ-বিহীন" সংস্করণ নির্দিষ্ট করে with। এখানে আমরা সহজেই বিভিন্ন অংশগুলি মোড়ানো করতে পারি try ... exceptএবং এইভাবে বিভিন্ন সম্ভাব্য ত্রুটি উত্সগুলির মধ্যে পার্থক্য করতে পারি:

import sys

try:
    mgr = ContextManager()
except ValueError as err:
    print('__init__ raised:', err)
else:
    try:
        value = type(mgr).__enter__(mgr)
    except ValueError as err:
        print('__enter__ raised:', err)
    else:
        exit = type(mgr).__exit__
        exc = True
        try:
            try:
                BLOCK
            except TypeError:
                pass
            except:
                exc = False
                try:
                    exit_val = exit(mgr, *sys.exc_info())
                except ValueError as err:
                    print('__exit__ raised:', err)
                else:
                    if not exit_val:
                        raise
        except ValueError as err:
            print('BLOCK raised:', err)
        finally:
            if exc:
                try:
                    exit(mgr, None, None, None)
                except ValueError as err:
                    print('__exit__ raised:', err)

সাধারণত একটি সহজ পদ্ধতির ঠিক জরিমানা করতে হবে

এই জাতীয় বিশেষ ব্যতিক্রম হ্যান্ডলিংয়ের প্রয়োজনটি বেশ বিরল হওয়া উচিত এবং সাধারণত withএকটি try ... exceptব্লকে পুরো মোড়ানোটি পর্যাপ্ত হবে। বিশেষত যদি বিভিন্ন ত্রুটি উত্সগুলি বিভিন্ন (কাস্টম) ব্যতিক্রম ধরণের দ্বারা নির্দেশিত হয় (প্রসঙ্গ পরিচালকদের সেই অনুযায়ী নকশা করা দরকার) আমরা সহজেই তাদের মধ্যে পার্থক্য করতে পারি। উদাহরণ স্বরূপ:

try:
    with ContextManager():
        BLOCK
except InitError:  # raised from __init__
    ...
except AcquireResourceError:  # raised from __enter__
    ...
except ValueError:  # raised from BLOCK
    ...
except ReleaseResourceError:  # raised from __exit__
    ...
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.