কিছু 'চেষ্টা' করা ভাল এবং ব্যতিক্রম ধরা বা পরীক্ষা করা যদি প্রথমে ব্যতিক্রম এড়ানো সম্ভব হয়?


139

আমার ifকিছু পরীক্ষা করা উচিত বৈধ কিনা বা কেবল এটি tryকরার জন্য এবং ব্যতিক্রমটি ধরা?

  • এমন কোনও শক্ত দলিল যা বলছে যে একদিকে অগ্রাধিকার দেওয়া হয়েছে?
  • এক উপায় কি আরও অজগর ?

উদাহরণস্বরূপ, আমার উচিত:

if len(my_list) >= 4:
    x = my_list[3]
else:
    x = 'NO_ABC'

বা:

try:
    x = my_list[3]
except IndexError:
    x = 'NO_ABC'

কিছু চিন্তা ...
পিইপি 20 বলেছেন:

ত্রুটিগুলি কখনই নিঃশব্দে কাটানো উচিত নয়।
স্পষ্টভাবে নিরব না হলে।

একটি tryপরিবর্তে এর পরিবর্তে একটি ব্যবহার করে ifনিঃশব্দে যাওয়ার সময় ত্রুটি হিসাবে ব্যাখ্যা করা উচিত? এবং যদি তাই হয়, আপনি কি এটিকে এভাবে ব্যবহার করে সুস্পষ্টভাবে চুপচাপ করছেন, সুতরাং এটি ঠিক আছে?


আমি এমন পরিস্থিতিতে উল্লেখ করছি না যেখানে আপনি কেবল 1 উপায়ে কাজ করতে পারেন; উদাহরণ স্বরূপ:

try:
    import foo
except ImportError:
    import baz

উত্তর:


161

ফলাফল যদি আসে তবে আপনার try/exceptচেয়ে বেশি পছন্দ করা উচিতif/else

  • গতি-আপগুলি (উদাহরণস্বরূপ অতিরিক্ত চেহারা প্রতিরোধের মাধ্যমে)
  • ক্লিনার কোড (কম লাইন / পড়তে সহজ)

প্রায়শই, এগুলি একসাথে যায়।


গতি আপগুলি

দীর্ঘ তালিকায় একটি উপাদান অনুসন্ধান করার চেষ্টা করার ক্ষেত্রে:

try:
    x = my_list[index]
except IndexError:
    x = 'NO_ABC'

indexসম্ভবত চেষ্টাটি তালিকার মধ্যে রয়েছে এবং সূচিপত্রটি সাধারণত উত্থাপিত না হলে ব্যতীত সেরা বিকল্পটি option এইভাবে আপনি দ্বারা অতিরিক্ত অনুসন্ধানের প্রয়োজন এড়ান if index < len(my_list)

পাইথন ব্যতিক্রমগুলির ব্যবহারকে উত্সাহ দেয়, যা আপনি হ্যান্ডেল করেন পাইথ ইন্ট পাইথনের একটি বাক্য । আপনাদের উদাহরণ না শুধুমাত্র ব্যতিক্রম (অত্যন্ত শৃঙ্খলার), বরং লেট তুলনায় এটি পরিচালনা চুপটি পাস , এছাড়াও ব্যতিক্রম শুধুমাত্র ঘটে ব্যতিক্রমী সূচক পাওয়া যায়নি হচ্ছে কেস (অত: পর শব্দ ব্যতিক্রম !)।


ক্লিনার কোড

অফিসিয়াল পাইথন ডকুমেন্টেশন ইএএফপি-র উল্লেখ করেছে : অনুমতি চেয়ে ক্ষমা চাওয়া সহজ এবং রব নাইট নোট করে যে ত্রুটিগুলি এড়িয়ে চলার পরিবর্তে ধরা পড়ার ফলে কোড পড়া সহজ, পরিচ্ছন্ন হতে পারে। তার উদাহরণ এটিকে বলে:

আরও খারাপ (LBYL 'আপনি লাফানোর আগে দেখুন') :

#check whether int conversion will raise an error
if not isinstance(s, str) or not s.isdigit():
    return None
elif len(s) > 10:    #too many digits for int conversion
    return None
else:
    return int(s)

আরও ভাল (ইএএফপি: অনুমতি চেয়ে ক্ষমা চাইতে সহজ) :

try:
    return int(s)
except (TypeError, ValueError, OverflowError): #int conversion failed
    return None

if index in mylistপরীক্ষাগুলি ওয়েদার সূচীটি আমার তালিকার একটি উপাদান, কোনও সম্ভাব্য সূচক নয়। আপনি if index < len(mylist)পরিবর্তে চান ।
ychaouche

1
এটি বোধগম্য হয় তবে আমি কোথায় ডকুমেন্টেশন পাই যেখানে এটি স্পষ্ট করে তোলে কোন সম্ভাব্য ব্যতিক্রমগুলি ইনট () এর জন্য ছোঁড়া যায় can docs.python.org/3/library/funitions.html#int আমি এই তথ্যটি এখানে খুঁজে পাচ্ছি না।
নিষ্ঠুরতা সরলতা

বিপরীতে, আপনি এই জবাবটি ( ডক অফ থেকে ) আপনার উত্তরে যুক্ত করতে পারেন, যখন আপনার if/elseচেয়ে পছন্দ করা উচিতtry/catch
রেপঙ্গি

20

এই বিশেষ ক্ষেত্রে, আপনার অন্য কিছু পুরোপুরি ব্যবহার করা উচিত:

x = myDict.get("ABC", "NO_ABC")

সাধারণভাবে, যদিও: আপনি পরীক্ষা, ঘন ঘন ব্যর্থ ব্যবহার আশা যদি if। পরীক্ষাটি যদি কেবল অপারেশন চেষ্টা করে ব্যর্থ হয় এবং ব্যর্থ হয় তবে ব্যর্থতা ধরা পড়লে, ব্যবহার করুন try। এই শর্তগুলির মধ্যে একটিও যদি না প্রযোজ্য তবে যা সহজ পড়বে তা দিয়ে যান।


1
কোড নমুনার অধীনে ব্যাখ্যার জন্য +1, যা স্পট রয়েছে।
ktdrv

4
আমি মনে করি এটি অত্যন্ত পরিষ্কার যে তিনি যা বলছিলেন তা নয়, এবং পোস্টটি আরও সুস্পষ্ট করার জন্য তিনি এখন সম্পাদনা করেছেন।
agf

9

কোনও প্রহরীর অভ্যন্তরের কোনও সম্ভাবনা থাকলে সর্বদা গার্ডের অভ্যন্তরের চেয়ে ব্যবহার করা tryএবং exceptসরাসরি করা ifউচিত । উদাহরণস্বরূপ, আপনি যদি কোনও ডিরেক্টরি বিদ্যমান থাকার বিষয়টি নিশ্চিত করতে চান তবে এটি করবেন না:

import os, sys
if not os.path.isdir('foo'):
  try:
    os.mkdir('foo')
  except OSError, e
    print e
    sys.exit(1)

অন্য থ্রেড বা প্রক্রিয়া মধ্যে ডিরেক্টরি তৈরি করে তাহলে isdirএবং mkdir, আপনি প্রস্থান করব। পরিবর্তে, এটি করুন:

import os, sys, errno
try:
  os.mkdir('foo')
except OSError, e
  if e.errno != errno.EEXIST:
    print e
    sys.exit(1)

কেবলমাত্র 'foo' ডিরেক্টরি তৈরি করা না গেলে এটি প্রস্থান করবে।


7

এটি করার আগে যদি কিছু ব্যর্থ হয় কিনা তা যদি তুচ্ছ হয় তবে আপনার সম্ভবত এটির পক্ষে নেওয়া উচিত। সর্বোপরি, ব্যতিক্রমগুলি (তাদের সম্পর্কিত ট্রেসব্যাকগুলি সহ) তৈরি করতে সময় লাগে।

ব্যতিক্রমগুলি এর জন্য ব্যবহার করা উচিত:

  1. অপ্রত্যাশিত, বা ...
  2. যে জিনিসগুলিতে আপনার একাধিক স্তরের যুক্তি ছোঁড়াতে হবে (যেমন যেখানে কোনও breakআপনাকে যথেষ্ট পরিমাণে পায় না), বা ...
  3. যে জিনিসগুলি আপনি জানেন না ঠিক কী আগে সময়ের ব্যতিক্রমটি পরিচালনা করবে বা ...
  4. ব্যর্থতার জন্য সময়ের আগে পরীক্ষা করা ব্যয়বহুল (কেবল অপারেশনের চেষ্টা করার সাথে সম্পর্কিত)

মনে রাখবেন যে প্রায়শই আসল উত্তরটি "হয় না" - উদাহরণস্বরূপ, আপনার প্রথম উদাহরণে আপনার যা করা উচিত তা কেবলমাত্র .get()একটি ডিফল্ট সরবরাহ করার জন্য ব্যবহার করা হয়:

x = myDict.get('ABC', 'NO_ABC')

দুর্ভাগ্যক্রমে যেটি if 'ABC' in myDict: x = myDict['ABC']; else: x = 'NO_ABC'ব্যবহার করার চেয়ে প্রায়শই দ্রুত হয় তা বাদ দিয়ে get। এটি সবচেয়ে গুরুত্বপূর্ণ মাপদণ্ড না বলা, তবে এটি সম্পর্কে সচেতন থাকার কিছু something
agf

@agf: পরিষ্কার এবং সংক্ষিপ্ত কোড লেখার চেয়ে আরও ভাল। যদি পরে কিছু অপ্টিমাইজ করা দরকার হয় তবে ফিরে আসা এবং এটি নতুন করে লেখা সহজ, তবে c2.com/cgi/wiki?PrematureOptimization
অ্যাম্বার

আমি জানি ; আমার বক্তব্যটি ছিল if / elseএবং কেস-সুনির্দিষ্ট বিকল্পtry / except থাকা সত্ত্বেও তাদের জায়গা থাকতে পারে কারণ তাদের পারফরম্যান্সের বৈশিষ্ট্য আলাদা।
agf

@ এএফএফ, আপনি কী জানেন যে ((কমপক্ষে)) স্পষ্টভাবে সন্ধানের জন্য তত দ্রুততর (কমপক্ষে) হওয়ার জন্য () পদ্ধতিটি উন্নত হবে কিনা? যাইহোক, দু'বার তাকানোর সময় (যেমন 'ডিবি: ডি [' এবিসি '] তে' এবিসি 'হিসাবে)) চেষ্টা করা হচ্ছে: ডি [' এবিসি '] কী-এরর ব্যতীত: ... দ্রুত নয়?
রেমি

2
@ রেমি এর ধীর অংশটি .get()পাইথন স্তরে অ্যাট্রিবিউট লুক এবং ফাংশন কল ওভারহেড; বিল্ট-ইনগুলিতে কীওয়ার্ডগুলি মূলত সি এর দিকে যায় বলে আমি মনে করি না যে খুব শীঘ্রই এটি খুব বেশি দ্রুত হয়ে উঠবে। যতক্ষণ না ifবনাম try, পড়ুন ডিক্টিমেট () পদ্ধতিটি একটি পয়েন্টার দেয় যা কিছু কার্য সম্পাদনের তথ্য দেয়। হিটের অনুপাত হ'ল ম্যাচটি মিস করে (অভিধানটি tryপ্রায়শই সর্বদা উপস্থিত থাকলে কীটি আরও দ্রুত হতে পারে) অভিধানের আকারের মতোই।
agf

5

অন্যান্য পোস্টে যেমন উল্লেখ করা হয়েছে, পরিস্থিতি নির্ভর করে on আগে থেকে আপনার ডেটার বৈধতা যাচাইয়ের জায়গায় চেষ্টা করে / বাদ দিয়ে কয়েকটি বিপদ রয়েছে, বিশেষত বড় প্রকল্পগুলিতে এটি ব্যবহার করার সময়।

  • চেষ্টা ব্লকের কোডটিতে ব্যতিক্রম ধরা পড়ার আগে সমস্ত প্রকারের সর্বনাশ চালানোর সুযোগ থাকতে পারে - যদি আপনি যদি ইতিবাচকভাবে একটি ইফ স্টেটমেন্ট দিয়ে আগে যাচাই করেন তবে আপনি এড়াতে পারবেন।
  • যদি আপনার ট্রাই ব্লকে ডাকা কোডটি একটি সাধারণ ব্যতিক্রম প্রকার যেমন টাইপআরর বা ভ্যালু এরির উত্থাপন করে তবে আপনি যে ব্যতিক্রমটি ধরার প্রত্যাশা করেছিলেন তা বাস্তবে নাও ধরতে পারে - এটি এমন অন্য কিছু হতে পারে যা এমনকি আগে বা তার পরেও একই ব্যতিক্রম শ্রেণিকে উত্থাপন করে আপনার ব্যতিক্রম উত্থাপিত হতে পারে যেখানে লাইন।

উদাহরণস্বরূপ, ধরুন আপনি ছিলেন:

try:
    x = my_list[index_list[3]]
except IndexError:
    x = 'NO_ABC'

ইনডেক্স-এরর সূচক_ তালিকা বা মাই-লিস্টের কোনও উপাদান পাওয়ার চেষ্টা করার সময় তা ঘটেছে কিনা সে সম্পর্কে কিছুই জানায় না।


4

চুপ করে যাওয়ার সময় একটি ত্রুটি হিসাবে ব্যাখ্যা করা যদি একটি পরিবর্তে একটি চেষ্টা ব্যবহার করা উচিত? এবং যদি তাই হয়, আপনি কি এটিকে এভাবে ব্যবহার করে সুস্পষ্টভাবে চুপচাপ করছেন, সুতরাং এটি ঠিক আছে?

ব্যবহারটি tryস্বীকার করছে যে কোনও ত্রুটি চলে যেতে পারে যা এটি নীরবে পাস করার বিপরীত। ব্যবহার exceptএটা সব সময়ে পাস না ঘটাচ্ছে।

যুক্তি আরও জটিল try: except:ক্ষেত্রে ক্ষেত্রে ব্যবহারকে পছন্দ করা হয় if: else:। জটিল জটিল চেয়ে সহজ; জটিল জটিল চেয়ে ভাল; এবং অনুমতি চেয়ে ক্ষমা চাইতে আরও সহজ।

"ত্রুটিগুলি কখনই নিঃশব্দে কাটানো উচিত নয়" সে সম্পর্কে সতর্ক করে দিচ্ছে, কোডটি এমন একটি ক্ষেত্রে যেখানে আপনার সম্পর্কে জানা ব্যতিক্রমগুলি উত্থাপন করতে পারে এবং যেখানে আপনার নকশাটি সম্ভাবনা স্বীকার করে, তবে আপনি ব্যতিক্রমটি মোকাবেলার জন্য কোনও নকশা তৈরি করেন নি। আমার দৃষ্টিতে কোনও ত্রুটি স্পষ্টভাবে নিঃশব্দ করা, passকোনও exceptব্লকের মতো কিছু করা হবে যা কেবল এই বোঝার সাথেই করা উচিত যে "পরিস্থিতি" কিছুই করা না করা নির্দিষ্ট পরিস্থিতিতে সঠিক ত্রুটি পরিচালনা করা। (এটি এমন কয়েকবারের মধ্যে যেখানে আমার মনে হয় সু-লিখিত কোডে কোনও মন্তব্য সম্ভবত মনে করা দরকার))

তবে আপনার নির্দিষ্ট উদাহরণে দুটিও উপযুক্ত নয়:

x = myDict.get('ABC', 'NO_ABC')

সবাই এটিকে নির্দেশ করার কারণ - যদিও আপনি সাধারণভাবে বোঝার আপনার আকাঙ্ক্ষাকে স্বীকৃতি দিয়েছেন এবং আরও ভাল উদাহরণ সহকারে আসার অক্ষমতা - এটি কি সমমানের পাশের পদক্ষেপগুলি আসলে বেশ কয়েকটি ক্ষেত্রে বিদ্যমান এবং তাদের সন্ধান করা হ'ল সমস্যা সমাধানের প্রথম পদক্ষেপ।


3

আপনি যখনই try/exceptনিয়ন্ত্রণ প্রবাহের জন্য ব্যবহার করবেন তখন নিজেকে জিজ্ঞাসা করুন:

  1. tryব্লকটি কখন সফল হয় এবং কখন এটি ব্যর্থ হয় তা কী সহজে দেখা যায় ?
  2. আপনি কি ব্লকের সমস্ত পার্শ্ব প্রতিক্রিয়া সম্পর্কে অবগত আছেন try?
  3. আপনি যে সমস্ত ক্ষেত্রে tryব্লকটি ব্যতিক্রম ছুঁড়ে ফেলেছেন সে সম্পর্কে কি আপনি সচেতন ?
  4. যদি tryব্লকটির বাস্তবায়ন পরিবর্তন হয়, আপনার নিয়ন্ত্রণ প্রবাহটি এখনও প্রত্যাশার সাথে আচরণ করবে?

এইগুলির মধ্যে এক বা একাধিক প্রশ্নের উত্তর যদি 'না' হয় তবে তার কাছে জিজ্ঞাসা করার জন্য অনেক ক্ষমা হতে পারে; আপনার ভবিষ্যতের স্ব থেকে সম্ভবত।


একটি উদাহরণ. আমি সম্প্রতি একটি বৃহত প্রকল্পে কোডটি দেখেছি যা দেখতে এইরকম দেখাচ্ছে:

try:
    y = foo(x)
except ProgrammingError:
    y = bar(x)

প্রোগ্রামারের সাথে কথা বলে জানা গেছে যে নিয়ন্ত্রিত নিয়ন্ত্রণ প্রবাহটি ছিল:

X যদি পূর্ণসংখ্যা হয় তবে y = foo (x) করুন।

X যদি পূর্ণসংখ্যার তালিকা হয় তবে y = বার (x) করুন।

এটি কাজ করেছে কারণ fooএকটি ডাটাবেস ক্যোয়ারী তৈরি হয়েছে এবং কোয়েরিটি সফল হবে যদি xকোনও পূর্ণসংখ্যা হয় এবং ProgrammingErrorযদি xএকটি তালিকা থাকে তবে তা ছুঁড়ে দেয় ।

এখানে ব্যবহার try/exceptকরা একটি খারাপ পছন্দ:

  1. ব্যতিক্রমটির নাম ProgrammingError, প্রকৃত সমস্যাটি দেয় না (এটি xকোনও পূর্ণসংখ্যার নয়), যা ঘটছে তা দেখতে অসুবিধা হয়।
  2. ProgrammingErrorএকটি ডাটাবেস কল, যা বর্জ্য সময়ে উত্থাপিত হয়। বিষয়গুলি সত্যই ভয়ঙ্কর হয়ে উঠবে যদি এটির fooকোনও ব্যতিক্রম ছুঁড়ে ফেলার আগে বা ডাটাবেসে কিছু লেখার আগে বা অন্য কোনও সিস্টেমের অবস্থার পরিবর্তন করে দেখা যায়।
  3. এটি পূর্ণসংখ্যার তালিকায় ProgrammingErrorকেবল যখন উত্থাপিত হয় তা অস্পষ্ট x। ধরুন উদাহরণস্বরূপ যে fooএর ডাটাবেস কোয়েরিতে একটি টাইপো রয়েছে । এটি একটি বাড়াতে পারে ProgrammingError। ফলাফলটি bar(x)এখন যখন xপূর্ণসংখ্যা হয় তখনও বলা হয়। এটি ক্রিপ্টিক ব্যতিক্রম বা অপ্রত্যাশিত ফলাফল উত্পাদন করতে পারে।
  4. try/exceptব্লক সমস্ত ভবিষ্যৎ বাস্তবায়নের জন্য একটি প্রয়োজন যোগ করা foo। যখনই আমরা পরিবর্তন করি foo, আমাদের এখন এটি কীভাবে তালিকাগুলি পরিচালনা করে তা নিয়ে চিন্তা করা উচিত এবং নিশ্চিত হওয়া উচিত যে এটি কোনওরকম বা কোনও ত্রুটি কোনওরকম নিক্ষেপ করে ProgrammingErrorএবং না AttributeError

0

একটি সাধারণ অর্থ, যদি আপনি পড়া বিবেচনা করতে পারে পাইথন মধ্যে বাগধারার এবং অ্যান্টি- বাগধারার: ব্যতিক্রমসমূহ

আপনার নির্দিষ্ট ক্ষেত্রে যেমন অন্যরা বলেছেন, আপনার ব্যবহার করা উচিত dict.get():

(কী [, ডিফল্ট]) পান

অভিধানে যদি কী থাকে তবে কীটির মানটি ফিরিয়ে দিন else যদি ডিফল্টটি দেওয়া না হয় তবে এটি ডিফল্ট নয় কারও সাথে, যাতে এই পদ্ধতিটি কখনই কী-ইরার উত্থাপন করে না।


আমি মনে করি না যে লিঙ্কটি এই পরিস্থিতিটি মোটেও coversেকে রাখে। এর উদাহরণগুলি প্রত্যাশিত পরিস্থিতিতে ব্যতিক্রম হ্যান্ডলিং ব্যবহার করবেন কিনা সে সম্পর্কে নয়, এমন আসল ত্রুটিগুলির প্রতিনিধিত্বকারী জিনিসগুলি পরিচালনা সম্পর্কে about
agf

প্রথম লিঙ্কটি পুরানো।
টিমোফেই বোন্ডারেভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.