যৌগিক 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
শৃঙ্খলা যুক্ত করতে পারি - যদি সেগুলি একই হয় তবে এর অর্থ হ'ল উত্সটি ছিল বা অন্যথায় এটি ছিল (ক্ষেত্রে যদি সত্যতম মানটি বহিরাগতকে ফেরত দিয়ে ব্যতিক্রমকে দমন করেwith
except
BLOCK
__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__
...
with
বিবৃতি ম্যাজিকভাবে পার্শ্ববর্তীtry...except
বিবৃতি ভঙ্গ করে না ।