পাইথনে "ইনার ব্যতিক্রম" (ট্রেসব্যাক সহ)?


146

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

যেমন। সি # তে আমি এরকম কিছু করব:

try
{
  ProcessFile(filePath);
}
catch (Exception ex)
{
  throw new ApplicationException("Failed to process file " + filePath, ex);
}

পাইথনে আমি অনুরূপ কিছু করতে পারি:

try:
  ProcessFile(filePath)
except Exception as e:
  raise Exception('Failed to process file ' + filePath, e)

... তবে এটি অন্তর্নিহিত ব্যতিক্রমগুলির ট্রেসব্যাক হারিয়ে ফেলে!

সম্পাদনা: আমি উভয় ব্যতিক্রম বার্তা এবং উভয় স্ট্যাক ট্রেস দেখতে এবং দুটি সংযুক্ত করতে চাই। এটি, আমি আউটপুটটিতে দেখতে চাই যে ব্যতিক্রম এক্স এখানে ঘটেছে এবং তারপরে Y সেখানে ব্যতিক্রম করবে - যা আমি সি # তে চাই। পাইথন ২.6 এ এটি কি সম্ভব? দেখে মনে হচ্ছে এখন পর্যন্ত আমি যা করতে পারি সেরা (গ্লেন মেইনার্ডের উত্তরের ভিত্তিতে):

try:
  ProcessFile(filePath)
except Exception as e:
  raise Exception('Failed to process file' + filePath, e), None, sys.exc_info()[2]

এটিতে বার্তা এবং উভয় ট্রেসব্যাক উভয়ই অন্তর্ভুক্ত রয়েছে তবে ট্রেসব্যাকটিতে কোন ব্যতিক্রম ঘটেছে তা তা দেখায় না।


3
গৃহীত উত্তরটি পুরানো হয়ে যাচ্ছে, সম্ভবত আপনার অন্য একটি গ্রহণ করার বিষয়টি বিবেচনা করা উচিত।
হারুন হলের

1
@AaronHall দুর্ভাগ্যবশত খুলছেনা প্রায় 2015. যেহেতু দেখা গেছে
Antti Haapala

উত্তর:


136

পাইথন 2

ইহা সহজ; তৃতীয় যুক্তি উত্থাপন হিসাবে ট্র্যাসব্যাক পাস।

import sys
class MyException(Exception): pass

try:
    raise TypeError("test")
except TypeError, e:
    raise MyException(), None, sys.exc_info()[2]

একটি ব্যতিক্রম ধরা এবং অন্যটিকে পুনরায় উত্থাপন করার সময় সর্বদা এটি করুন।


4
ধন্যবাদ। এটি ট্রেসব্যাক সংরক্ষণ করে তবে এটি মূল ব্যতিক্রমটির ত্রুটি বার্তাটি হারায়। আমি উভয় বার্তা এবং উভয় ট্রেসব্যাক দেখতে পারি?
EMP

6
raise MyException(str(e)), ..., ইত্যাদি
গ্লেন মেইনার্ড

23
পাইথন 3 যোগ করেছে raise E() from tbএবং.with_traceback(...)
ডিমা তিস্নেক

3
@ গ্লেনমায়নার্ড এটি একটি বেশ পুরানো প্রশ্ন, তবে এর মধ্যের যুক্তিটি raiseব্যতিক্রমটি পাস করার মান ((প্রথম যুক্তি যদি ব্যতিক্রম শ্রেণি হয় এবং উদাহরণ নয়)। তাই আপনি যদি এর পরিবর্তে করছেন, swap 'র ব্যতিক্রম করতে চান raise MyException(str(e)), None, sys.exc_info()[2], এটা এই ব্যবহার করা ভাল: raise MyException, e.args, sys.exc_info()[2]
বিগুসাচ

8
ভবিষ্যতের প্যাকেজটি ব্যবহার করে একটি পাইথন 2 এবং 3 কমপ্লায়েন্ট উপায় সম্ভব: পাইথন-ফিউচার.আর.কম / সামঞ্জস্যপূর্ণ_আইডিওমস html#raising- ব্যতিক্রম উদাহরণ from future.utils import raise_এবং raise_(ValueError, None, sys.exc_info()[2])
jtpereyda

239

পাইথন ঘ

অজগর 3 এ আপনি নিম্নলিখিতগুলি করতে পারেন:

try:
    raise MyExceptionToBeWrapped("I have twisted my ankle")

except MyExceptionToBeWrapped as e:

    raise MyWrapperException("I'm not in a good shape") from e

এটি এর মতো কিছু তৈরি করবে:

   Traceback (most recent call last):
   ...
   MyExceptionToBeWrapped: ("I have twisted my ankle")

The above exception was the direct cause of the following exception:

   Traceback (most recent call last):
   ...
   MyWrapperException: ("I'm not in a good shape")

17
raise ... from ...পাইথন 3 এ এটি করার সঠিক উপায় হ'ল এটির আরও উন্নতি প্রয়োজন।
নেকেডেবল

Nakedibleআমার মনে হয় কারণ দুর্ভাগ্যক্রমে বেশিরভাগ মানুষ পাইথন 3 ব্যবহার করেন না
টিম লুডবিনস্কি


পাইথন 2 এ ব্যাকপোর্ট করা যায় Hope আশা করি এটি একদিন হবে।
ওয়াজনারস্কি

4
@ogrisel আপনি এটি futureঅর্জন করতে প্যাকেজটি ব্যবহার করতে পারেন : পাইথন-ফিউচার.আর.কম্প্যাটিড_আইডিওমস html#raising- ব্যতিক্রম উদাহরণ from future.utils import raise_এবং raise_(ValueError, None, sys.exc_info()[2])
jtpereyda

19

পাইথন 3 এর চেন ব্যতিক্রমগুলির raise... fromধারা রয়েছে । পাইথন ২.7 এর জন্য গ্লেনের উত্তর দুর্দান্ত, তবে এটি কেবল আসল ব্যতিক্রমগুলির ট্রেসব্যাক ব্যবহার করে এবং ত্রুটি বার্তা এবং অন্যান্য বিবরণকে ছুঁড়ে ফেলে। পাইথন ২.7-এর কয়েকটি উদাহরণ এখানে মূল ব্যতিক্রমের ত্রুটি বার্তায় বর্তমান সুযোগ থেকে প্রাসঙ্গিক তথ্য যুক্ত করে তবে অন্যান্য বিবরণ অক্ষত রাখে।

পরিচিত ব্যতিক্রম প্রকার

try:
    sock_common = xmlrpclib.ServerProxy(rpc_url+'/common')
    self.user_id = sock_common.login(self.dbname, username, self.pwd)
except IOError:
    _, ex, traceback = sys.exc_info()
    message = "Connecting to '%s': %s." % (config['connection'],
                                           ex.strerror)
    raise IOError, (ex.errno, message), traceback

যে গন্ধ raiseবিবৃতি প্রথম অভিব্যক্তি, দ্বিতীয় অভিব্যক্তি হিসাবে একটি tuple মধ্যে ব্যতিক্রম বর্গ কনস্ট্রাকটর আর্গুমেন্ট এবং তৃতীয় অভিব্যক্তি হিসাবে ট্রেসব্যাক যেমন ব্যতিক্রম টাইপ লাগে। আপনি যদি পাইথন ২.২-র তুলনায় আগে চালাচ্ছেন তবে সতর্কতাগুলি দেখুন sys.exc_info()

যে কোনও ব্যতিক্রম প্রকার

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

except Exception:
    extype, ex, tb = sys.exc_info()
    formatted = traceback.format_exception_only(extype, ex)[-1]
    message = "Importing row %d, %s" % (rownum, formatted)
    raise RuntimeError, message, tb

বার্তাটি পরিবর্তন করুন

ব্যতিক্রমের ধরণটি আপনাকে এটিতে প্রসঙ্গ যুক্ত করতে দিলে এখানে আরও একটি বিকল্প রয়েছে। আপনি ব্যতিক্রমের বার্তাটি সংশোধন করতে পারেন এবং তারপরে এটি আবার পুনরায় করতে পারেন।

import subprocess

try:
    final_args = ['lsx', '/home']
    s = subprocess.check_output(final_args)
except OSError as ex:
    ex.strerror += ' for command {}'.format(final_args)
    raise

এটি নিম্নলিখিত স্ট্যাক ট্রেস উত্পন্ন করে:

Traceback (most recent call last):
  File "/mnt/data/don/workspace/scratch/scratch.py", line 5, in <module>
    s = subprocess.check_output(final_args)
  File "/usr/lib/python2.7/subprocess.py", line 566, in check_output
    process = Popen(stdout=PIPE, *popenargs, **kwargs)
  File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1327, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory for command ['lsx', '/home']

আপনি দেখতে পাচ্ছেন যে এটি যেখানে check_output()ডাকা হয়েছিল সেই লাইনটি দেখায় , তবে ব্যতিক্রম বার্তায় এখন কমান্ড লাইন রয়েছে।


1
কোথা ex.strerrorথেকে আসছে? পাইথন ডক্সে এর জন্য আমি কোনও প্রাসঙ্গিক হিট পাই না। এটা করা উচিত নয় str(ex)?
হেনরিক হিমবুর্গার

1
IOErrorEnvironmentError@hheimbuerger থেকে উদ্ভূত , যা গুণাবলী errornoএবং strerrorবৈশিষ্ট্যগুলি সরবরাহ করে।
ডন কার্কবি

আমি কিভাবে একটি অবাধ মোড়ানো হবে Error, যেমন ValueError, একটি মধ্যে RuntimeErrorসংক্রামক দ্বারা Exception? আমি যদি এই মামলার জন্য আপনার উত্তর পুনরুত্পাদন করি তবে স্ট্যাকট্র্যাসটি হারিয়ে গেছে।
কার্ল রিখটার

আপনি কী জিজ্ঞাসা করছেন তা আমি নিশ্চিত নই, @ কার্ল। আপনি কি নতুন প্রশ্নে একটি নমুনা পোস্ট করতে পারেন এবং তারপরে এখান থেকে লিঙ্ক করতে পারেন?
ডন কার্কবি

আমি আপনার উত্তরটি সরাসরি বিবেচনায় নিয়ে একটি স্পষ্টকরণের সাথে স্ট্যাকওভারফ্লো . com/ জিজ্ঞাসাগুলি / 23157766 /… এ ওপি-র প্রশ্নের আমার নকল সম্পাদনা করেছি । আমাদের সেখানে আলোচনা করা উচিত :)
কার্ল রিখটার

12

ইন পাইথন 3.x :

raise Exception('Failed to process file ' + filePath).with_traceback(e.__traceback__)

বা সহজভাবে

except Exception:
    raise MyException()

যা প্রচার করে MyExceptionতবে উভয় ব্যতিক্রম মুদ্রণ করে যদি এটি পরিচালনা না করা হয়।

ইন পাইথন 2.x :

raise Exception, 'Failed to process file ' + filePath, e

আপনি __context__গুনটি মেরে উভয় ব্যতিক্রম মুদ্রণ প্রতিরোধ করতে পারেন । ফ্লাইতে আপনার ব্যতিক্রমটি ধরতে এবং পরিবর্তন করতে এখানে আমি একটি প্রসঙ্গ পরিচালক ব্যবহার করে লিখছি: ( তারা কীভাবে কাজ করে তার বিস্তারের জন্য http://docs.python.org/3.1/library/stdtypes.html দেখুন )

try: # Wrap the whole program into the block that will kill __context__.

    class Catcher(Exception):
        '''This context manager reraises an exception under a different name.'''

        def __init__(self, name):
            super().__init__('Failed to process code in {!r}'.format(name))

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            if exc_type is not None:
                self.__traceback__ = exc_tb
                raise self

    ...


    with Catcher('class definition'):
        class a:
            def spam(self):
                # not really pass, but you get the idea
                pass

            lut = [1,
                   3,
                   17,
                   [12,34],
                   5,
                   _spam]


        assert a().lut[-1] == a.spam

    ...


except Catcher as e:
    e.__context__ = None
    raise

4
প্রকারের ত্রুটি: উত্থাপন: আরগ 3 অবশ্যই একটি ট্রেসব্যাক বা কোনও নয়
গ্লেন মেইনার্ড

দুঃখিত, আমি একটি ভুল করেছি, একরকম আমি ভেবেছিলাম এটি ব্যতিক্রমগুলিও গ্রহণ করে এবং তাদের ট্রেসব্যাক বৈশিষ্ট্যটি স্বয়ংক্রিয়ভাবে পায়। অনুযায়ী docs.python.org/3.1/reference/... , এই ই .__ traceback__ হওয়া উচিত
ilya এন।

1
@ ইলিয়ান .: পাইথন 2 এর e.__traceback__বৈশিষ্ট্য নেই!
জানু হুডেক

5

পাইথন ২.x এ আপনি এটি করতে পারবেন বলে আমি মনে করি না, তবে এই কার্যকারিতার সাথে কিছু মিল পাইথনের ৩ অংশ on পিইপি 3134 থেকে :

আজকের পাইথন বাস্তবায়নে ব্যতিক্রমগুলি তিনটি অংশ নিয়ে গঠিত: প্রকার, মান এবং ট্রেসব্যাক। 'সিস' মডিউলটি বর্তমান ব্যতিক্রমটিকে তিনটি সমান্তরাল ভেরিয়েবল, এক্স_প্লে, টাইপ, এক্স_ভ্যালু এবং এক্স_ট্র্যাসব্যাকে প্রকাশ করে, sys.exc_info () ফাংশনটি এই তিনটি অংশের একটি অংশ দেয় এবং 'উত্থাপন' বিবৃতিটিতে একটি ত্রি-যুক্তি রূপ গ্রহণ করে এই তিনটি অংশ। ব্যতিক্রমগুলি পরিচালনা করার জন্য প্রায়শই এই তিনটি জিনিসকে সমান্তরালে পাস করা প্রয়োজন, যা ক্লান্তিকর এবং ত্রুটি-প্রবণ হতে পারে। অতিরিক্ত হিসাবে, 'বাদে' বিবৃতিটি কেবল মানটিতে অ্যাক্সেস সরবরাহ করতে পারে, ট্রেসব্যাক নয়। যোগ করা হচ্ছে 'ব্যতিক্রম মানগুলিতে ট্রেসব্যাক ' বৈশিষ্ট্য যুক্ত করা সমস্ত ব্যতিক্রম তথ্যকে একক স্থান থেকে অ্যাক্সেসযোগ্য করে তোলে।

সি # এর সাথে তুলনা:

সি # এর ব্যতিক্রমগুলিতে একটি পঠনযোগ্য কেবলমাত্র কেবলমাত্র 'অভ্যন্তরীণ ধারণা' বৈশিষ্ট্য রয়েছে যা অন্য কোনও ব্যতিক্রমকে নির্দেশ করতে পারে। এর ডকুমেন্টেশন [10] বলে যে "পূর্ববর্তী ব্যতিক্রমের ওয়াইয়ের প্রত্যক্ষ ফলাফল হিসাবে এক্স ব্যতিক্রম এক্স নিক্ষেপ করা হয়, এক্স এর অভ্যন্তরীণ এক্সপ্রেশন সম্পত্তিটিতে ওয়াইয়ের একটি উল্লেখ থাকতে হবে।" এই সম্পত্তিটি স্বয়ংক্রিয়ভাবে ভিএম দ্বারা সেট করা হয়নি; পরিবর্তে, সমস্ত ব্যতিক্রম নির্মাতারা এটি সুস্পষ্টভাবে সেট করতে একটি alচ্ছিক 'অভ্যন্তরীণ ধারণা "যুক্তি গ্রহণ করে। ' কারণ ' বৈশিষ্ট্যটি অভ্যন্তরীণ ধারণা হিসাবে একই উদ্দেশ্য পূরণ করে, তবে এই পিইপি সমস্ত ব্যাতিক্রমকারীর নির্মাণকারীর প্রসারণ না করে 'উত্থাপন' এর একটি নতুন রূপের প্রস্তাব দেয়। সি # এছাড়াও একটি গেটবেস এক্সসেপশন পদ্ধতি সরবরাহ করে যা সরাসরি ইনার এক্সসেপশন চেইনের শেষের দিকে লাফ দেয়;

আরও লক্ষ করুন যে জাভা, রুবি এবং পার্ল 5 এই ধরণের জিনিসটিকেও সমর্থন করে না। আবার উদ্ধৃতি:

অন্যান্য ভাষার হিসাবে, জাভা এবং রুবি উভয়ই মূল ব্যতিক্রমটিকে বাতিল করে যখন 'ক্যাচ' / 'রেসকিউ' বা 'অবশেষে' / 'নিশ্চিতকরণ' ধারাটিতে অন্য একটি ব্যতিক্রম ঘটে। পার্ল 5 এর অন্তর্নির্মিত কাঠামোগত ব্যতিক্রম হ্যান্ডলিংয়ের অভাব রয়েছে। পার্ল 6 এর জন্য, আরএফসি নম্বর 88 [9] একটি ব্যতিক্রম প্রক্রিয়া প্রস্তাব করে যা স্পষ্টতই @@ নামের অ্যারেটিতে শৃঙ্খলযুক্ত ব্যতিক্রমগুলি বজায় রাখে।


তবে, অবশ্যই, পার্ল 5 এ আপনি কেবল "qise। OH NOES! $ @}" স্বীকার করতে পারেন এবং অন্য ব্যতিক্রমের স্ট্যাক ট্রেসটি হারাবেন না। অথবা আপনি নিজের ধরণের প্রয়োগ করতে পারেন যা ব্যতিক্রম ধরে রাখে।
জারকওয়ে

4

পাইথন 2 এবং 3 এর মধ্যে সর্বাধিক সামঞ্জস্য জন্য, আপনি ব্যবহার করতে পারেন raise_fromমধ্যে sixগ্রন্থাগার। https://six.readthedocs.io/#six.raise_from । এখানে আপনার উদাহরণ (স্পষ্টতার জন্য সামান্য পরিবর্তিত):

import six

try:
  ProcessFile(filePath)
except Exception as e:
  six.raise_from(IOError('Failed to process file ' + repr(filePath)), e)

3

পাইথন ২.x এর ব্যতিক্রমগুলি শৃঙ্খলাবদ্ধ করতে আপনি আমার কাউসেক্সেপশন ক্লাসটি ব্যবহার করতে পারেন (এবং পাইথন 3 তেও আপনি যদি নতুন উত্থাপিত ব্যতিক্রমের কারণ হিসাবে একাধিক ধরা ব্যতিক্রম দিতে চান তবে এটি কার্যকর হতে পারে)। হতে পারে এটি আপনাকে সাহায্য করতে পারে।


2

সম্ভবত আপনি প্রাসঙ্গিক তথ্য দখল এবং এটি পাস করতে পারে? আমি এরকম কিছু ভাবছি:

import traceback
import sys
import StringIO

class ApplicationError:
    def __init__(self, value, e):
        s = StringIO.StringIO()
        traceback.print_exc(file=s)
        self.value = (value, s.getvalue())

    def __str__(self):
        return repr(self.value)

try:
    try:
        a = 1/0
    except Exception, e:
        raise ApplicationError("Failed to process file", e)
except Exception, e:
    print e

2

ধরে নেওয়া যাক:

  • আপনার একটি সমাধান দরকার যা পাইথন 2 এর জন্য কাজ করে (খাঁটি পাইথন 3 এর raise ... fromসমাধান দেখুন)
  • কেবল ত্রুটি বার্তাটি সমৃদ্ধ করতে চান, উদাহরণস্বরূপ কিছু অতিরিক্ত প্রসঙ্গ সরবরাহ করা
  • সম্পূর্ণ স্ট্যাক ট্রেস প্রয়োজন

আপনি ডক্স থেকে একটি সহজ সমাধান ব্যবহার করতে পারেন https://docs.python.org/3/tutorial/erferences.html#raising- ব্যতিক্রম :

try:
    raise NameError('HiThere')
except NameError:
    print 'An exception flew by!' # print or log, provide details about context
    raise # reraise the original exception, keeping full stack trace

আউটপুট:

An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

দেখে মনে হচ্ছে কী টুকরোটি সরলিকৃত 'উত্থাপন' কীওয়ার্ড যা একা দাঁড়িয়ে। এটি বাদে বাদে ব্যতিক্রমটিকে পুনরায় উত্থাপন করবে।


এটি পাইথন 2 এবং 3 সামঞ্জস্যপূর্ণ সমাধান! ধন্যবাদ!
অ্যান্ডি চেস

আমি মনে করি ধারণাটি ছিল ভিন্ন ধরণের ব্যতিক্রম বাড়াতে।
টিম লুডবিনস্কি

2
এটি নেস্টেড ব্যতিক্রমগুলির একটি শৃঙ্খল নয়, কেবল একটি ব্যতিক্রম পুনর্বিবেচনা
কার্ল রিখটার

এটি সর্বোত্তম পাইথন 2 সমাধান, যদি আপনার কেবলমাত্র ব্যতিক্রম বার্তাটি সমৃদ্ধ করা উচিত এবং সম্পূর্ণ স্ট্যাক ট্রেস পাওয়া দরকার!
geekQ

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