পাইথন: আমি কীভাবে জানতে পারি যে কোনও পদ্ধতি কল থেকে কোন ব্যতিক্রমগুলি ছোঁড়া হতে পারে


89

পাইথন কোডটি কার্যকর করার সময় ব্যতিক্রমগুলি আশা করার কোন উপায় রয়েছে (কোডিংয়ের সময়)? আমি ব্যতিক্রম ব্যাতিক্রমটি 90% সময় ধরে ধরেছি যেহেতু আমি জানি না কোন ব্যতিক্রম প্রকারটি নিক্ষেপ করা হতে পারে (এবং আমাকে ডকুমেন্টেশন পড়তে বলবেন না times অনেক সময় গভীর থেকে ব্যতিক্রম প্রচার করা যায় and এবং অনেকগুলি ডকুমেন্টেশন বার আপডেট বা সঠিক না হয়)। এটি পরীক্ষা করার জন্য কি কোনও ধরণের সরঞ্জাম রয়েছে? (পাইথন কোড এবং লিবস পড়ে)?


4
মনে রাখবেন যে পাইথন <২.6 এ আপনি কেবল raiseস্ট্রিংগুলিতেও স্ট্রিং করতে পারেন BaseException। সুতরাং আপনি যদি লাইব্রেরি কোডটিতে কল করছেন যা আপনার নিয়ন্ত্রণের বাইরে রয়েছে, এমনকি except Exceptionএটি পর্যাপ্ত নয়, কারণ এটি স্ট্রিং ব্যতিক্রমগুলি ধরবে না। অন্যরা যেমন উল্লেখ করেছে, আপনি এখানে ভুল গাছটি ছাঁটাই করছেন।
ড্যানিয়েল প্রাইডেন

আমি এটা জানতাম না। আমি ব্যাতিক্রম ব্যতীত ভেবেছিলাম: .. প্রায় সব কিছু ধরা পড়ে।
গাবীমে

4
except Exceptionপাইথন ২.6 এবং তারপরে স্ট্রিং ব্যতিক্রমগুলি ধরার জন্য দুর্দান্ত কাজ করে।
জেফ্রি হ্যারিস

উত্তর:


22

আমার ধারণা, স্থির টাইপিংয়ের নিয়মের অভাবে কোনও সমাধান কেবল অনর্থক হতে পারে।

আমি এমন কোনও সরঞ্জাম সম্পর্কে অবগত নই যা ব্যতিক্রমগুলি যাচাই করে তবে আপনি নিজের প্রয়োজনগুলির সাথে মিলিয়ে নিজের সরঞ্জামটি নিয়ে আসতে পারেন (স্থির বিশ্লেষণের সাথে কিছুটা খেলার ভাল সুযোগ)।

প্রথম প্রয়াস হিসাবে, আপনি এমন একটি ফাংশন লিখতে পারেন যা একটি এএসটি তৈরি করে, সমস্ত Raiseনোড সন্ধান করে এবং তারপরে ব্যতিক্রম উত্থাপনের সাধারণ প্যাটার্নগুলি সনাক্ত করার চেষ্টা করে (যেমন সরাসরি কোনও কনস্ট্রাক্টরকে কল করা)

xনিম্নলিখিত প্রোগ্রাম হতে দিন :

x = '''\
if f(x):
    raise IOError(errno.ENOENT, 'not found')
else:
    e = g(x)
    raise e
'''

compilerপ্যাকেজটি ব্যবহার করে এএসটি তৈরি করুন :

tree = compiler.parse(x)

তারপরে একটি Raiseদর্শনার্থী শ্রেণি নির্ধারণ করুন :

class RaiseVisitor(object):
    def __init__(self):
        self.nodes = []
    def visitRaise(self, n):
        self.nodes.append(n)

এবং এএসটি সংগ্রহকারী Raiseনোডগুলি হাঁটা :

v = RaiseVisitor()
compiler.walk(tree, v)

>>> print v.nodes
[
    Raise(
        CallFunc(
            Name('IOError'),
            [Getattr(Name('errno'), 'ENOENT'), Const('not found')],
            None, None),
        None, None),
    Raise(Name('e'), None, None),
]

আপনি সংকলক প্রতীক টেবিলগুলি ব্যবহার করে প্রতীকগুলি সমাধান করে, ডেটা নির্ভরতা ইত্যাদি বিশ্লেষণ করে চালিয়ে যেতে পারেন বা আপনি কেবল অনুমান করতে পারেন, CallFunc(Name('IOError'), ...)"অবশ্যই IOError" উত্থাপনের অর্থ হওয়া উচিত ", যা দ্রুত ব্যবহারিক ফলাফলের জন্য বেশ ঠিক আছে :)


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

4
v.nodesউপরের মানটি দেওয়া , আপনি আসলে বলতে পারবেন না যে জিনিসটি কী Name('IOError')বা Name('e')। আপনি কী জানেন যে সেগুলি কী (গুলি) IOErrorএবং eএটি নির্দেশ করতে পারে, কারণ তারা তথাকথিত মুক্ত ভেরিয়েবল। এমনকি যদি তাদের বাধ্যতামূলক প্রসঙ্গটি জানা থাকে (এখানে প্রতীক টেবিলগুলি কার্যকর হয়) তবে তাদের সঠিক মানগুলি নির্ধারণের জন্য আপনার এক ধরণের ডেটা নির্ভরতা বিশ্লেষণ করা উচিত (এটি পাইথনের ক্ষেত্রে কঠোর হওয়া উচিত)।
আন্দ্রে ভ্লাসোভস্কিখ

আপনি যেমন ব্যবহারিক আধা-স্বয়ংক্রিয় সমাধানের সন্ধান করছেন, ['IOError(errno.ENOENT, "not found")', 'e']ব্যবহারকারীর কাছে প্রদর্শিত একটি তালিকা ঠিক আছে। তবে আপনি স্ট্রিং দ্বারা প্রতিনিধিত্বযোগ্য ভেরিয়েবলের মানগুলির প্রকৃত শ্রেণি নির্ধারণ করতে পারবেন না (পুনরায় পোস্ট করার জন্য দুঃখিত)
আন্দ্রে ভ্লাসভস্কিখ

4
হ্যাঁ. এই পদ্ধতিটি যদিও চালাক, আসলে আপনাকে একটি সম্পূর্ণ কভারেজ দেয় না। পাইথনের গতিশীল প্রকৃতির কারণে আপনি কোডটির জন্য এমন কিছু করার জন্য যে কোডটি কল করছেন তা পুরোপুরি সম্ভব (যদিও স্পষ্টতই একটি খারাপ ধারণা) exc_class = raw_input(); exec "raise " + exc_class। মুল বক্তব্যটি হ'ল পাইথনের মতো গতিশীল ভাষায় এই ধরণের স্থির বিশ্লেষণ সত্যই সম্ভব নয়।
ড্যানিয়েল প্রাইডেন

7
যাইহোক, আপনি কেবল find /path/to/library -name '*.py' | grep 'raise 'একই ফলাফল পেতে পারেন :)
আন্দ্রে ভ্লাসাভস্কিখ

23

আপনার কেবলমাত্র ব্যতিক্রমগুলি ধরা উচিত যা আপনি পরিচালনা করবেন।

সমস্ত ব্যতিক্রমগুলি তাদের কংক্রিটের ধরণের মাধ্যমে ধরা মজাদার is আপনি যে নির্দিষ্ট ব্যতিক্রম করতে পারবেন তা ধরতে হবে এবং পরিচালনা করতে পারবে। অন্যান্য ব্যতিক্রমগুলির জন্য, আপনি একটি জেনেরিক ক্যাচ লিখতে পারেন যা "বেস এক্সেপশন" ক্যাচ করে, এটি লগ করে ( str()ফাংশনটি ব্যবহার করে) এবং আপনার প্রোগ্রামটি সমাপ্ত করে (বা ক্র্যাশ পরিস্থিতিতে উপযুক্ত এমন অন্য কিছু করে)।

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

আপনি ভাষা ব্যতিক্রম রেফারেন্সে আগ্রহী হতে পারেন , আপনি যে লাইব্রেরিটি ব্যবহার করছেন তার কোনও রেফারেন্স নয়।

যদি লাইব্রেরির রেফারেন্সটি সত্যই দুর্বল হয় এবং সিস্টেমটি ধরার সময় এটি তার নিজস্ব ব্যতিক্রমগুলি আবার ছুঁড়ে না ফেলে তবে একমাত্র দরকারী পন্থা হল পরীক্ষা চালানো (সম্ভবত এটি টেস্ট স্যুটে যুক্ত করা যায়, কারণ যদি কোনও কিছু স্বাক্ষরিত না হয় তবে এটি পরিবর্তন হতে পারে!) । আপনার কোডের জন্য গুরুত্বপূর্ণ একটি ফাইল মুছুন এবং কী ব্যতিক্রম ছুঁড়েছে তা পরীক্ষা করুন। অত্যধিক ডেটা সরবরাহ করুন এবং এতে কী ত্রুটি পাওয়া যায় তা পরীক্ষা করুন।

আপনাকে যে কোনও উপায়েই পরীক্ষা চালাতে হবে, যেহেতু উত্স কোড দ্বারা ব্যতিক্রম পাওয়ার পদ্ধতিটি বিদ্যমান থাকলেও এটি আপনাকে কীভাবে পরিচালনা করতে হবে সে সম্পর্কে কোনও ধারণা দেয় না । হতে পারে আপনার ত্রুটি বার্তাটি দেখানো উচিত "ফাইলের প্রয়োজনীয়: টেক্সট পাওয়া যায় নি!" কবে ধর IndexError? কেবল পরীক্ষা বলতে পারে।


27
অবশ্যই, তবে কী কী ছোঁড়া হতে পারে তা যদি না জানে তবে কীভাবে তার ব্যতিক্রমগুলি পরিচালনা করা উচিত তা কীভাবে সিদ্ধান্ত নিতে পারে ??
গাবীমে

@ বাগস্পাই নেট, এই বিষয়টি প্রতিফলিত করার জন্য আমার উত্তর স্থির করেছেন
পি শেভ করা হয়েছে

হতে পারে এটি উত্স কোড বিশ্লেষকের জন্য সময় যা এটি খুঁজে পেতে পারে? আমার মনে হয় বিকাশ করা খুব কঠিন হওয়া উচিত নয়
গ্যাবিমে

@ বাগস্পাই.এন.এ, আমি যে ধারাটি এটির জন্য সময় হতে পারে তা আমি উত্সাহিত করেছি।
পি

নিশ্চিত আপনি ঠিক আছেন। তবে এটি এখনও আকর্ষণীয় হতে পারে - বিকাশের সময় - কোন ধরণের ব্যতিক্রম হতে পারে তা জানতে।
hek2mgl

11

এই সমস্যাটি সমাধানের সঠিক সরঞ্জামটি ইউনিটেটস। আপনি যদি ইউনিটেটগুলি উত্থাপন না করে এমন সত্যিকারের কোড দ্বারা উত্থাপিত ব্যতিক্রমগুলি থেকে থাকে তবে আপনার আরও ইউনিটেটস প্রয়োজন।

এই বিবেচনা

def f(duck):
    try:
        duck.quack()
    except ??? could be anything

হাঁস যে কোনও বস্তু হতে পারে

স্পষ্টতই আপনার AttributeErrorযদি একটি হাঁসের কোনও TypeErrorকোক থাকে না তবে একটি হাঁসের একটি কোক থাকে তবে এটি কলযোগ্য নয়। আপনার duck.quack()উত্সাহ নেই তবে কী উত্থাপিত হতে পারে, এমনকি এমনকি DuckErrorকিছু বা কিছু

এখন ধরুন আপনার কাছে এই জাতীয় কোড রয়েছে

arr[i] = get_something_from_database()

যদি এটি উত্থাপিত হয় তবে IndexErrorআপনি জানেন না যে এটি আরআর [i] থেকে এসেছে বা ডাটাবেস ফাংশনের গভীর থেকে এসেছে। সাধারণত যেখানে ব্যতিক্রম ঘটেছিল তা এতটা গুরুত্বপূর্ণ নয়, বরং কিছু ভুল হয়েছে এবং আপনি যা করতে চেয়েছিলেন তা ঘটেছিল না।

একটি সহজ কৌশল ধরা এবং সম্ভবত এটির মতো ব্যতিক্রম পুনরায় সাজানো

except Exception as e
    #inspect e, decide what to do
    raise

আপনি যদি এটি "পুনরায় সংশোধন" করতে চলেছেন তবে কেন একেবারে ধরবেন?
তার্নে কলমেন

আপনি না আছে এটা reraise হয়, যে কি মন্তব্য ইঙ্গিত অনুমিত ছিল।
জন লা রোয়

4
আপনি কোথাও ব্যতিক্রমটি লগ ইন করতে এবং তারপরে পুনরায় সংশোধন করতে পারেন
জন লা

4
আমি মনে করি না যে লেখার ইউনিট পরীক্ষাগুলি উত্তর the প্রশ্নটি "কী কী ব্যতিক্রম প্রত্যাশা করা উচিত তা আমি কীভাবে খুঁজে বের করতে পারি" এবং ইউনিট পরীক্ষাগুলি লেখার বিষয়টি আপনাকে এটি খুঁজে পেতে সহায়তা করবে না। প্রকৃতপক্ষে, ইউনিট পরীক্ষাটি লিখতে আপনাকে ইতিমধ্যে জানতে হবে যে কোন ব্যাতিক্রমের প্রত্যাশা করা উচিত তাই সঠিক ইউনিট পরীক্ষা লেখার জন্য আপনাকে মূল প্রশ্নটিও যুক্ত করতে হবে।
ব্রুনো র্যানচেয়ার্ট

6

নুন এখনও পর্যন্ত ব্যাখ্যা করেছেন, আপনার কেন ব্যতিক্রমগুলির একটি পূর্ণ, 100% সঠিক তালিকা থাকতে পারে না, তাই আমি ভেবেছিলাম এটি সম্পর্কে মন্তব্য করা উপযুক্ত। এর অন্যতম কারণ হ'ল প্রথম শ্রেণির ফাংশন। আসুন আমরা এইভাবে বলি যে আপনার মত একটি ফাংশন রয়েছে:

def apl(f,arg):
   return f(arg)

এখন aplযে কোনও ব্যতিক্রম fউত্থাপন করতে পারে। মূল লাইব্রেরিতে এর মতো অনেকগুলি ক্রিয়াকলাপ না থাকলেও কাস্টম ফিল্টার, মানচিত্র, হ্রাস ইত্যাদির সাহায্যে তালিকার বোঝাপড়া ব্যবহার করে এমন কোনও কিছুই প্রভাবিত হয়।

ডকুমেন্টেশন এবং উত্স বিশ্লেষকরা এখানে তথ্যের একমাত্র "গুরুতর" উত্স। তারা কী করতে পারে না কেবল তা মনে রাখবেন।


5

সকেট ব্যবহার করার সময় আমি এটির মধ্যে দৌড়ে গিয়েছিলাম, আমি যে সমস্ত ত্রুটি শর্তটি নিয়ে যাব তা জানতে চেয়েছিলাম (ত্রুটিগুলি তৈরি করার চেষ্টা করার চেয়ে আমি কী সকেটটি কেবল একটি সংক্ষিপ্ত তালিকা চাইছিলাম তা খুঁজে বের করার চেয়ে)। শেষ পর্যন্ত আমি "উত্থাপন" এর জন্য গ্রেপিং "/usr/lib64/python2.4/test/test_sket.py" শেষ করেছি:

$ grep raise test_socket.py
Any exceptions raised by the clients during their tests
        raise TypeError, "test_func must be a callable function"
    raise NotImplementedError, "clientSetUp must be implemented."
    def raise_error(*args, **kwargs):
        raise socket.error
    def raise_herror(*args, **kwargs):
        raise socket.herror
    def raise_gaierror(*args, **kwargs):
        raise socket.gaierror
    self.failUnlessRaises(socket.error, raise_error,
    self.failUnlessRaises(socket.error, raise_herror,
    self.failUnlessRaises(socket.error, raise_gaierror,
        raise socket.error
    # Check that setting it to an invalid value raises ValueError
    # Check that setting it to an invalid type raises TypeError
    def raise_timeout(*args, **kwargs):
    self.failUnlessRaises(socket.timeout, raise_timeout,
    def raise_timeout(*args, **kwargs):
    self.failUnlessRaises(socket.timeout, raise_timeout,

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


4
এটি আমার যুক্তিটিকে শক্তিশালী করে, পাইথনে ব্যতিক্রম হ্যান্ডেলিং খুব সমস্যাযুক্ত, যদি আমাদের এত কিছু বেসিক (যেমন উদাহরণস্বরূপ জাভাতে প্রথম থেকেই বিদ্যমান ছিল) কিছু ক্ষেত্রে ভার্বোসিসিটি ভাল জিনিস হিসাবে কাজ করার জন্য গ্রেপ বা উত্স বিশ্লেষক ব্যবহার করার প্রয়োজন হয় তবে জাভা ভার্জিক তবে কমপক্ষে কোনও
দুষ্টু

@ গ্যাবিমে, এই ক্ষমতাটি (বা সাধারণভাবে স্ট্যাটিক টাইপিং) পছন্দ হয় না এটি সমস্ত বাগ প্রতিরোধের জন্য রৌপ্য বুলেট। জাভা দুষ্টু আশ্চর্য পূর্ণ । যে কারণে নিয়মিতভাবে গ্রহণ ক্রাশ হয়।
জন লা রুয়ে

2

দুটি উপায় আছে যা আমি তথ্যপূর্ণ পেয়েছি। প্রথমটি, আইপাইথনে কোড চালান যা ব্যতিক্রম প্রকারটি প্রদর্শন করবে।

n = 2
str = 'me '
str + 2
TypeError: unsupported operand type(s) for +: 'int' and 'str'

দ্বিতীয় উপায়ে আমরা খুব বেশি ধরা পড়ার জন্য নিষ্পত্তি করি এবং সময়ের সাথে সাথে এটিতে উন্নতি করি। tryআপনার কোড এবং ক্যাচ একটি অভিব্যক্তি অন্তর্ভুক্ত করুন except Exception as err। কী ব্যতিক্রম ছুঁড়েছিল তা জানতে পর্যাপ্ত ডেটা মুদ্রণ করুন। ব্যতিক্রমগুলি নিক্ষেপ করার সাথে সাথে আরও সুনির্দিষ্ট exceptধারা যুক্ত করে আপনার কোডের উন্নতি করতে হবে । আপনি যখন মনে করেন যে আপনি সমস্ত প্রাসঙ্গিক ব্যতিক্রমগুলি ধরা পড়েছেন তখন সমস্ত অন্তর্ভুক্তিকে সরিয়ে দিন। যাইহোক একটি ভাল কাজ কারণ এটি প্রোগ্রামিং ত্রুটিগুলি গ্রাস করে।

try:
   so something
except Exception as err:
   print "Some message"
   print err.__class__
   print err
   exit(1)

1

সাধারণত, আপনাকে কোডের কয়েকটি লাইনের আশেপাশে ব্যতিক্রম ধরা দরকার। আপনি আপনার পুরো mainফাংশনটি try exceptধারাটিতে রাখতে চান না । প্রতি কয়েকটি লাইনের জন্য আপনার সর্বদা এখনই (বা সহজেই পরীক্ষা করতে সক্ষম হওয়া উচিত) কোন ধরণের ব্যতিক্রম উত্থাপিত হতে পারে।

দস্তাবেজের অন্তর্নির্মিত ব্যতিক্রমগুলির একটি সম্পূর্ণ তালিকা রয়েছে । আপনি যে প্রত্যাশা করছেন না সেগুলি বাদ দেওয়ার চেষ্টা করবেন না, সেগুলি কলিং কোডে পরিচালনা / প্রত্যাশিত হতে পারে।

সম্পাদনা করুন : নিক্ষেপ করা কি হতে পারে তা আপনি যা করছেন তার উপর নির্ভর করে! অনুক্রমের এলোমেলো উপাদান অ্যাক্সেস করা IndexError:, একটি ডিকের এলোমেলো উপাদান: KeyErrorইত্যাদি etc.

কেবল আইডলিতে এই কয়েকটি লাইন চালানোর চেষ্টা করুন এবং একটি ব্যতিক্রম ঘটায়। তবে ইউনিটেস্ট প্রাকৃতিকভাবেই এর থেকে ভাল সমাধান হতে পারে।


4
এটি আমার সাধারণ প্রশ্নের উত্তর দিচ্ছে না। আমি কীভাবে আমার ব্যতিক্রম হ্যান্ডলিং ডিজাইন করব, বা কখন বা কীভাবে ধরব তা জিজ্ঞাসা করি না। আমি কীভাবে ছুঁড়ে ফেলা হতে পারে তা কীভাবে জানতে হবে
GabiMe

4
@ বাগস্পাই নেট: আপনি যা চান তা করা অসম্ভব এবং এটি পুরোপুরি বৈধ কাজ।
ড্যানিয়েল প্রাইডেন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.