ব্যতিক্রম তথ্য যুক্ত?


142

আমি এরকম কিছু অর্জন করতে চাই:

def foo():
   try:
       raise IOError('Stuff ')
   except:
       raise

def bar(arg1):
    try:
       foo()
    except Exception as e:
       e.message = e.message + 'happens at %s' % arg1
       raise

bar('arg1')
Traceback...
  IOError('Stuff Happens at arg1')

তবে আমি যা পাই তা হ'ল:

Traceback..
  IOError('Stuff')

এটি কীভাবে অর্জন করা যায় সে সম্পর্কে কোনও সূত্র? পাইথন 2 এবং 3 এ এটি কীভাবে করবেন?


ব্যতিক্রমী messageবৈশিষ্ট্যের জন্য ডকুমেন্টেশন সন্ধান করার সময় আমি এই এসও প্রশ্নটি পেয়েছি, বেসএক্সেপশন.ম্যাসেজ পাইথন ২.6 এ অবমূল্যায়িত হয়েছে , যা দেখে মনে হয় যে এর ব্যবহারটি এখন নিরুৎসাহিত করা হয়েছে (এবং কেন এটি ডক্সে নেই)।
মার্টিনিউ

দুঃখের বিষয়, সেই লিঙ্কটি আর কাজ করবে বলে মনে হচ্ছে না।
মাইকেল স্কট কুথবার্ট


বার্তা বৈশিষ্ট্যের স্থিতি কী এবং আর্গস বৈশিষ্ট্য এবং পিইপি 352 এর সাথে এর সম্পর্ক কী তা সম্পর্কে এখানে একটি দুর্দান্ত ব্যাখ্যা । এটি বিনামূল্যে বই থেকে স্টিভেন এফ লোটের পাইথনের বিল্ডিং স্কিলস
মার্টিনো

উত্তর:


118

আমি এটি এটির মতো করব যাতে এর ধরণের foo()পরিবর্তন করাও এটির পরিবর্তনের প্রয়োজন হবে না bar()

def foo():
    try:
        raise IOError('Stuff')
    except:
        raise

def bar(arg1):
    try:
        foo()
    except Exception as e:
        raise type(e)(e.message + ' happens at %s' % arg1)

bar('arg1')

Traceback (most recent call last):
  File "test.py", line 13, in <module>
    bar('arg1')
  File "test.py", line 11, in bar
    raise type(e)(e.message + ' happens at %s' % arg1)
IOError: Stuff happens at arg1

আপডেট 1

এখানে একটি সামান্য পরিবর্তন রয়েছে যা মূল ট্রেসব্যাক সংরক্ষণ করে:

...
def bar(arg1):
    try:
        foo()
    except Exception as e:
        import sys
        raise type(e), type(e)(e.message +
                               ' happens at %s' % arg1), sys.exc_info()[2]

bar('arg1')

Traceback (most recent call last):
  File "test.py", line 16, in <module>
    bar('arg1')
  File "test.py", line 11, in bar
    foo()
  File "test.py", line 5, in foo
    raise IOError('Stuff')
IOError: Stuff happens at arg1

আপডেট 2

পাইথন ৩.x এর জন্য, আমার প্রথম আপডেটের কোডটি সিনট্যাক্টিক্যালি ভুল এবং একটি থাকার ধারণাটি message উপর অ্যাট্রিবিউট BaseExceptionহয় PEP 352 করার জন্য একটি পরিবর্তন প্রত্যাহৃত 2012-05-16 উপর (আমার প্রথম আপডেট 2012-03-12 পোস্ট করা হয়েছে) । সুতরাং বর্তমানে পাইথন 3.5.৩.২ তে যাইহোক, আপনার ট্রেসব্যাক সংরক্ষণের জন্য এই লাইনগুলি বরাবর কিছু করতে হবে এবং ফাংশনে ব্যতিক্রমের ধরণের হার্ডকোডটি নয় bar()। আরও মনে রাখবেন যে লাইনটি থাকবে:

During handling of the above exception, another exception occurred:

প্রদর্শিত ট্রেসব্যাক বার্তায়।

# for Python 3.x
...
def bar(arg1):
    try:
        foo()
    except Exception as e:
        import sys
        raise type(e)(str(e) +
                      ' happens at %s' % arg1).with_traceback(sys.exc_info()[2])

bar('arg1')

আপডেট 3

একজন মন্তব্যকারী জিজ্ঞাসা করেছিলেন যে পাইথন 2 এবং 3 উভয় ক্ষেত্রেই এমন কোন উপায় রয়েছে যা উত্তরটি সিনট্যাক্সের পার্থক্যের কারণে উত্তর "না" বলে মনে হতে পারে, তবে সেখানে হয় মত একটি সাহায্যকারী ফাংশন ব্যবহার করে যে কাছাকাছি একটি উপায় reraise()মধ্যে sixadd- মডিউল উপর। সুতরাং, আপনি যদি কোনও কারণে লাইব্রেরিটি ব্যবহার না করতে চান তবে নীচে একটি সরলীকৃত একক সংস্করণ দেওয়া আছে।

আরও খেয়াল করুন, যেহেতু ব্যতিক্রমটি ফাংশনটির মধ্যে পুনরায় সংশোধন করা হয়েছে reraise(), তাই যা কিছু ট্রেসব্যাক উত্থাপিত হবে তাতে উপস্থিত হবে, তবে চূড়ান্ত ফলাফল যা আপনি চান তা।

import sys

if sys.version_info.major < 3:  # Python 2?
    # Using exec avoids a SyntaxError in Python 3.
    exec("""def reraise(exc_type, exc_value, exc_traceback=None):
                raise exc_type, exc_value, exc_traceback""")
else:
    def reraise(exc_type, exc_value, exc_traceback=None):
        if exc_value is None:
            exc_value = exc_type()
        if exc_value.__traceback__ is not exc_traceback:
            raise exc_value.with_traceback(exc_traceback)
        raise exc_value

def foo():
    try:
        raise IOError('Stuff')
    except:
        raise

def bar(arg1):
    try:
       foo()
    except Exception as e:
        reraise(type(e), type(e)(str(e) +
                                 ' happens at %s' % arg1), sys.exc_info()[2])

bar('arg1')

3
এটি ব্যাকট্রেস হারায়, একটি বিদ্যমান ব্যতিক্রম তথ্য যুক্ত করার পয়েন্টকে পরাস্ত করে। এছাড়াও, এটির সাথে ব্যতিক্রমগুলি কাজ করে না যা> 1 টি আর্গুমেন্ট গ্রহণ করে (প্রকারটি এমন কিছু জায়গা যেখানে আপনি ব্যতিক্রমটি ধরেন সেই জায়গা থেকে আপনি নিয়ন্ত্রণ করতে পারবেন না)।
ভ্যাক্লাভ স্লাভক

1
@ ভ্যাক্লাভ: ব্যাকট্র্যাস হারাতে বাধা দেওয়া মোটামুটি সহজ - আমি যোগ করা আপডেটে দেখানো হয়েছে। যদিও এটি এখনও প্রতিটি অনুমেয় ব্যতিক্রম পরিচালনা করে না, এটি ওপি-র প্রশ্নে যেমন দেখানো হয়েছিল তার মতো মামলাগুলির জন্য কাজ করে।
মার্টিনিউ

1
এই নয় বেশ ঠিক আছে। যদি (ঙ) ওভাররাইড হয় তবে __str__আপনি অযাচিত ফলাফল পেতে পারেন। এছাড়াও মনে রাখবেন যে দ্বিতীয় আর্গুমেন্টটি প্রথম আর্গুমেন্ট দ্বারা প্রদত্ত কন্সট্রাক্টরের কাছে দেওয়া হয়েছে, যা কিছুটা অযৌক্তিক ফল দেয় type(e)(type(e)(e.message)। তৃতীয়ত, e.mgsage ই.আরগস [0] এর পক্ষে অবচয় করা হয়
বুকজোর

1
সুতরাং, কোনও পোর্টেবল উপায় নেই যা পাইথন 2 এবং 3 উভয় ক্ষেত্রেই কাজ করে?
ইলিয়াস ডরনেলেস

1
@ মার্টিনাউ ব্লক বাদে আমদানির উদ্দেশ্য কী? এটি কি প্রয়োজন হলে কেবল আমদানি করে মেমরি সঞ্চয় করা যায়?
অল ট্রেডস জ্যাক

115

যদি আপনি পাইথন 3 এর সমাধান অনুসন্ধান করতে এসেছিলেন তবে ম্যানুয়ালটিতে বলা হয়েছে:

কোনও নতুন ব্যতিক্রম উত্থাপন করার সময় ( raiseবর্তমানে পরিচালিত ব্যতিক্রমটিকে পুনরায় উত্থাপনের জন্য খালি ব্যবহারের পরিবর্তে ) অন্তর্নিহিত ব্যতিক্রম প্রসঙ্গটি উত্থাপিত থেকে ব্যবহার করে একটি সুস্পষ্ট কারণে পরিপূরক করা যেতে পারে:

raise new_exc from original_exc

উদাহরণ:

try:
    return [permission() for permission in self.permission_classes]
except TypeError as e:
    raise TypeError("Make sure your view's 'permission_classes' are iterable. "
                    "If you use '()' to generate a set with a single element "
                    "make sure that there is a comma behind the one (element,).") from e

যা শেষ পর্যন্ত এরকম দেখাচ্ছে:

2017-09-06 16:50:14,797 [ERROR] django.request: Internal Server Error: /v1/sendEmail/
Traceback (most recent call last):
File "venv/lib/python3.4/site-packages/rest_framework/views.py", line 275, in get_permissions
    return [permission() for permission in self.permission_classes]
TypeError: 'type' object is not iterable 

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

Traceback (most recent call last):
    # Traceback removed...
TypeError: Make sure your view's Permission_classes are iterable. If 
     you use parens () to generate a set with a single element make 
     sure that there is a (comma,) behind the one element.

TypeErrorআসল ব্যতিক্রম ব্যর্থ না করে সমাধানের দিকে ইঙ্গিত সহ পুরোপুরি ননডিস্ক্রিপ্টকে সুন্দর বার্তায় পরিণত করা।


14
এটি সর্বোত্তম সমাধান, যেহেতু ফলস্বরূপ ব্যতিক্রমটি মূল কারণকে নির্দেশ করে, আরও বিশদ সরবরাহ করে।
জেটি

এমন কোনও সমাধান আছে যা আমরা কিছু বার্তা যুক্ত করতে পারি তবে এখনও একটি নতুন ব্যতিক্রম বাড়াতে পারি না? আমি কেবল ব্যতিক্রম উদাহরণটির বার্তা প্রসারিত করতে চাইছি।
এডিসিএসএম

ইয়া ~~ এটি কাজ করে তবে এটি এমন কিছু মনে হয় যা আমার সাথে করা উচিত নয়। বার্তাটি সঞ্চিত আছে e.argsতবে এটি একটি টিপল, তাই এটি পরিবর্তন করা যায় না। সুতরাং প্রথমে argsএকটি তালিকায় অনুলিপি করুন , তারপরে এটি সংশোধন করুন, তারপরে এটি আবার একটি টিপল হিসাবে অনুলিপি করুন:args = list(e.args) args[0] = 'bar' e.args = tuple(args)
ক্রিস

27

ধরে নিই যে আপনি foo () বা সংশোধন করতে চান না বা করতে পারেন না, আপনি এটি করতে পারেন:

try:
    raise IOError('stuff')
except Exception as e:
    if len(e.args) >= 1:
        e.args = (e.args[0] + ' happens',) + e.args[1:]
    raise

এখানে প্রকৃতপক্ষে একমাত্র সমাধান যা পাইথন 3 এ সমস্যাটি কুৎসিত এবং বিভ্রান্তিমূলক ছাড়াই সমাধান করে "উপরের ব্যতিক্রমটি পরিচালনা করার সময়, অন্য একটি ব্যতিক্রম ঘটেছিল" বার্তাটি।

যদি পুনরায় উত্থাপনের লাইনটি স্ট্যাক ট্রেসের সাথে যুক্ত করা উচিত তবে raise eপরিবর্তে লেখার raiseকৌশলটি কৌশলটি করবে।


তবে এই ক্ষেত্রে যদি foo এ ব্যতিক্রম পরিবর্তন হয় তবে আমাকে বারটিও ঠিক পরিবর্তন করতে হবে?
আনিজওয়া

1
আপনি যদি ব্যতিক্রম ধরেন (উপরে সম্পাদিত), আপনি যেকোন স্ট্যান্ডার্ড গ্রন্থাগার ব্যতিক্রম (পাশাপাশি যেগুলি ব্যতিক্রম থেকে উত্তরাধিকারসূত্রে আসে এবং ব্যতিক্রমটিকে কল করে __ init__) ধরতে পারেন।
স্টিভ হাওয়ার্ড

6
আরও সম্পূর্ণ / সমবায় হতে, মূল টিপলের অন্যান্য অংশগুলি অন্তর্ভুক্ত করুন:e.args = ('mynewstr' + e.args[0],) + e.args[1:]
ডাবস্লো 31'18

1
@ nmz787 বাস্তবে পাইথন 3 এর জন্য এটি সেরা সমাধান। আপনার ত্রুটি ঠিক কী?
খ্রিস্টান

1
@ ডাবস্লো এবং মার্টিনো আমি আপনার পরামর্শগুলি একটি সম্পাদনায় অন্তর্ভুক্ত করেছি।
খ্রিস্টান

9

আমি এখনও পর্যন্ত প্রদত্ত সমস্ত উত্তর পছন্দ করি না। তারা এখনও খুব ভার্জোজ ইমো। উভয় কোড এবং বার্তা আউটপুট।

আমি যা করতে চাই তা হ'ল উত্স ব্যতিক্রমের দিকে ইঙ্গিত করে স্ট্যাকট্রেস, এর মধ্যে কোনও ব্যতিক্রম সামগ্রী নেই, তাই নতুন ব্যতিক্রমগুলির কোনও সৃষ্টি নয়, কেবলমাত্র এতে সমস্ত প্রাসঙ্গিক স্ট্যাক ফ্রেমের রাজ্যগুলির সাথে মূলটিকে পুনরায় উত্থাপন করতে হবে, যা সেখানে নেতৃত্ব দিয়েছে।

স্টিভ হাওয়ার্ড একটি দুর্দান্ত উত্তর দিয়েছেন যা আমি প্রসার করতে চাই, না, হ্রাস করুন ... কেবলমাত্র অজগর 3 তে।

except Exception as e:
    e.args = ("Some failure state", *e.args)
    raise

কেবলমাত্র নতুন জিনিসটি হল প্যারামিটারের সম্প্রসারণ / আনপ্যাকিং যা এটি আমার পক্ষে ব্যবহারের পক্ষে ছোট এবং যথেষ্ট সহজ করে তোলে।

এটি চেষ্টা করুন:

foo = None

try:
    try:
        state = "bar"
        foo.append(state)

    except Exception as e:
        e.args = ("Appending '"+state+"' failed", *e.args)
        raise

    print(foo[0]) # would raise too

except Exception as e:
    e.args = ("print(foo) failed: " + str(foo), *e.args)
    raise

এটি আপনাকে দেবে:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    foo.append(state)
AttributeError: ('print(foo) failed: None', "Appending 'bar' failed", "'NoneType' object has no attribute 'append'")

একটি সাধারণ সুন্দর-মুদ্রণের মতো কিছু হতে পারে

print("\n".join( "-"*i+" "+j for i,j in enumerate(e.args)))

5

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

class CustomError(Exception):
    def __init__(self, details: Dict):
        self.details = details

তারপরে আপনার কোডে:

raise CustomError({'data': 5})

এবং একটি ত্রুটি ধরা যখন:

except CustomError as e:
    # Do whatever you want with the exception instance
    print(e.details)

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

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

2

পূর্ববর্তী উত্তরের মতো নয়, এটি সত্যিই খারাপ ব্যতিক্রমগুলির ক্ষেত্রে কাজ করে __str__। এটা তোলে করেন আউট অকেজো ফ্যাক্টর তবে টাইপ সংশোধন করে, যাতে__str__ বাস্তবায়নের।

আমি এখনও একটি অতিরিক্ত উন্নতি সন্ধান করতে চাই যা এই ধরণের পরিবর্তন করে না।

from contextlib import contextmanager
@contextmanager
def helpful_info():
    try:
        yield
    except Exception as e:
        class CloneException(Exception): pass
        CloneException.__name__ = type(e).__name__
        CloneException.__module___ = type(e).__module__
        helpful_message = '%s\n\nhelpful info!' % e
        import sys
        raise CloneException, helpful_message, sys.exc_traceback


class BadException(Exception):
    def __str__(self):
        return 'wat.'

with helpful_info():
    raise BadException('fooooo')

মূল ট্রেসব্যাক এবং প্রকার (নাম) সংরক্ষণ করা হয়েছে।

Traceback (most recent call last):
  File "re_raise.py", line 20, in <module>
    raise BadException('fooooo')
  File "/usr/lib64/python2.6/contextlib.py", line 34, in __exit__
    self.gen.throw(type, value, traceback)
  File "re_raise.py", line 5, in helpful_info
    yield
  File "re_raise.py", line 20, in <module>
    raise BadException('fooooo')
__main__.BadException: wat.

helpful info!

2

আমি যখনই কোনও ব্যতিক্রমে অতিরিক্ত তথ্য যুক্ত করতে চাই তখন আমি কোডের একটি স্নিপেট সরবরাহ করব। আমি পাইথন 2.7 এবং 3.6 এ উভয়ই কাজ করি।

import sys
import traceback

try:
    a = 1
    b = 1j

    # The line below raises an exception because
    # we cannot compare int to complex.
    m = max(a, b)  

except Exception as ex:
    # I create my  informational message for debugging:
    msg = "a=%r, b=%r" % (a, b)

    # Gather the information from the original exception:
    exc_type, exc_value, exc_traceback = sys.exc_info()

    # Format the original exception for a nice printout:
    traceback_string = ''.join(traceback.format_exception(
        exc_type, exc_value, exc_traceback))

    # Re-raise a new exception of the same class as the original one, 
    # using my custom message and the original traceback:
    raise type(ex)("%s\n\nORIGINAL TRACEBACK:\n\n%s\n" % (msg, traceback_string))

উপরের কোডটি নিম্নলিখিত ফলাফলের ফলাফল:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-09b74752c60d> in <module>()
     14     raise type(ex)(
     15         "%s\n\nORIGINAL TRACEBACK:\n\n%s\n" %
---> 16         (msg, traceback_string))

TypeError: a=1, b=1j

ORIGINAL TRACEBACK:

Traceback (most recent call last):
  File "<ipython-input-6-09b74752c60d>", line 7, in <module>
    m = max(a, b)  # Cannot compare int to complex
TypeError: no ordering relation is defined for complex numbers


আমি জানি যে এটি প্রশ্নের প্রদত্ত উদাহরণ থেকে কিছুটা বিচ্যুত হয়েছে তবে তবুও আমি আশা করি যে কেউ এটির কাজে লাগবে।


1

আপনি নিজের ব্যতিক্রমটি সংজ্ঞায়িত করতে পারেন যা অন্যের কাছ থেকে উত্তরাধিকার সূত্রে প্রাপ্ত এবং মান নির্ধারণের জন্য এটির নিজস্ব নির্মাতা তৈরি করতে পারে।

উদাহরণ স্বরূপ:

class MyError(Exception):
   def __init__(self, value):
     self.value = value
     Exception.__init__(self)

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

2
messageমূল ব্যতিক্রমটির ঠিকানার কোনও কিছু পরিবর্তন / সংযোজন করার প্রয়োজন নেই (তবে এটি স্থির করা যেতে পারে, আমি মনে করি)।
মার্টিনিউ

-6

হতে পারে

except Exception as e:
    raise IOError(e.message + 'happens at %s'%arg1)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.