পাইথনে একটি কাস্টম বার্তা দিয়ে আমি কীভাবে একই ব্যতিক্রম বাড়িয়ে তুলব?


145

আমার tryকোডটিতে আমার এই ব্লকটি রয়েছে:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise ValueError(errmsg)

কঠোরভাবে বলতে, আমি আসলে উত্থাপন করছি আরেকটি ValueError না ValueErrorদ্বারা নিক্ষিপ্ত do_something...(), যা হিসাবে উল্লেখ করা হয় errএই ক্ষেত্রে। আমি কীভাবে একটি কাস্টম বার্তা সংযুক্ত করব err? আমি নিচের কোডটি চেষ্টা কিন্তু কারণে ব্যর্থ হয় err, একটি ValueError উদাহরণ হিসেবে বলা যায় , callable হচ্ছে না:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise err(errmsg)

13
@ হামিশ, অতিরিক্ত তথ্য সংযুক্ত করা এবং পুনরায় উত্থাপন ব্যতিক্রমগুলি ডিবাগ করার সময় খুব সহায়ক হতে পারে।
জোহান লন্ডবার্গ

@ জোহান একেবারে - এবং এটি একটি স্ট্যাকট্রেসের জন্য। আপনি কেন নতুন ত্রুটি উত্থাপনের পরিবর্তে বিদ্যমান ত্রুটি বার্তাটি সম্পাদনা করবেন তা পুরোপুরি বুঝতে পারি না।
হামিশ

@Hamish। অবশ্যই তবে আপনি অন্যান্য জিনিস যোগ করতে পারেন। আপনার প্রশ্নের জন্য, আমার উত্তর এবং ইউনিকোডডেকোডেরর উদাহরণটি দেখুন। যদি আপনার মন্তব্য থাকে তবে পরিবর্তে আমার উত্তরটি মন্তব্য করুন।
জোহান লন্ডবার্গ


1
@ কিট এটি 2020 এবং অজগর 3 সর্বত্র রয়েছে। বেনের উত্তরের গ্রহণযোগ্য উত্তরটি কেন পরিবর্তন করবেন না :-)
এমআইটি

উত্তর:


88

আপডেট: পাইথন 3 এর জন্য, বেনের উত্তর পরীক্ষা করুন


বর্তমান ব্যতিক্রমের সাথে একটি বার্তা সংযুক্ত করতে এবং এটি পুনরায় উত্থাপন করতে: (বাহ্যিক চেষ্টা / বাদে কেবল প্রভাবটি দেখানো হয়)

পাইথন 2.x এর জন্য যেখানে x> = 6:

try:
    try:
      raise ValueError  # something bad...
    except ValueError as err:
      err.message=err.message+" hello"
      raise              # re-raise current exception
except ValueError as e:
    print(" got error of type "+ str(type(e))+" with message " +e.message)

এটাও ডান জিনিস কি করতে হবে যদি errহয় উদ্ভূত থেকে ValueError। উদাহরণস্বরূপ UnicodeDecodeError

মনে রাখবেন যে আপনি যা চান তা যুক্ত করতে পারেন err। উদাহরণস্বরূপ err.problematic_array=[1,2,3]


সম্পাদনা: @ ডুকান একটি মন্তব্যে পয়েন্টগুলি উপরের পাইথন 3 এর সাথে কাজ করে না যেহেতু এর .messageসদস্য নয় ValueError। পরিবর্তে আপনি এটি ব্যবহার করতে পারেন (বৈধ অজগর 2.6 বা তারপরে বা 3.x):

try:
    try:
      raise ValueError
    except ValueError as err:
       if not err.args: 
           err.args=('',)
       err.args = err.args + ("hello",)
       raise 
except ValueError as e:
    print(" error was "+ str(type(e))+str(e.args))

Edit2:

উদ্দেশ্য কী তার উপর নির্ভর করে আপনি নিজের ভেরিয়েবল নামের অধীনে অতিরিক্ত তথ্য যুক্ত করার বিকল্প বেছে নিতে পারেন। পাইথন 2 এবং পাইথন 3 উভয়ের জন্য:

try:
    try:
      raise ValueError
    except ValueError as err:
       err.extra_info = "hello"
       raise 
except ValueError as e:
    print(" error was "+ str(type(e))+str(e))
    if 'extra_info' in dir(e):
       print e.extra_info

9
যেহেতু আপনি পাইথন 3 স্টাইলের ব্যতিক্রম হ্যান্ডলিং ব্যবহারের প্রয়াসে গিয়েছেন এবং printআপনার সম্ভবত উল্লেখ করা উচিত যে আপনার কোডটি পাইথন 3.x messageতে কাজ করে না কারণ ব্যতিক্রমগুলির কোনও বৈশিষ্ট্য নেই । err.args = (err.args[0] + " hello",) + err.args[1:]আরও নির্ভরযোগ্যভাবে কাজ করতে পারে (এবং তারপরে কেবল বার্তাটি পাওয়ার জন্য একটি স্ট্রিংয়ে রূপান্তর করুন)।
ডানকান

1
দুর্ভাগ্যক্রমে কোনও গ্যারান্টি নেই যে আরগস [0] একটি ত্রুটি বার্তার প্রতিনিধিত্বকারী একটি স্ট্রিং টাইপ - "ব্যতিক্রম নির্মাণকারীকে দেওয়া আর্গুমেন্টের টিপল Some কিছু বিল্ট-ইন ব্যতিক্রম (আইওআরারের মতো) নির্দিষ্ট সংখ্যক যুক্তি প্রত্যাশা করে এবং একটি বিশেষ অর্থ নির্ধারণ করে এই টিপলের উপাদানগুলি, অন্যদের সাধারণত ত্রুটি বার্তা দেওয়ার জন্য কেবল একটি একক স্ট্রিং দিয়ে ডাকা হয় " সুতরাং কোডটি আরগ করবে না [0] কোনও ত্রুটি বার্তা নয় (এটি কোনও int হতে পারে, বা এটি কোনও ফাইলের প্রতিনিধিত্বকারী স্ট্রিং হতে পারে)।
ট্রেন্ট

1
@ তারাস, আকর্ষণীয়। আপনার কি এটার রেফারেন্স আছে? তারপরে আমি সম্পূর্ণ নতুন সদস্য যুক্ত করব: err.my_own_extra_info। বা নতুন এবং মূল তথ্য রেখে আমার নিজস্ব ব্যতিক্রমগুলিতে এগুলি সমস্তই encapsulate করুন।
জোহান লন্ডবার্গ

2
যখন আরগস [0] এর ত্রুটি বার্তা না হয় তার প্রকৃত উদাহরণ - docs.python.org/2/library/exception.html - "ব্যতিক্রম পরিবেশের ত্রুটি পাইথন সিস্টেমের বাইরে যে ব্যতিক্রম ঘটতে পারে তার জন্য বেস ক্লাস: আইওআরর, ওএসরর। যখন এই ধরণের ব্যতিক্রমগুলি একটি 2-টিপল দিয়ে তৈরি করা হয়, প্রথম আইটেমটি উদাহরণের এররুন অ্যাট্রিবিউটে পাওয়া যায় (এটি একটি ত্রুটি সংখ্যা হিসাবে ধরে নেওয়া হয়) এবং দ্বিতীয় আইটেমটি স্ট্রিরর বৈশিষ্ট্যে পাওয়া যায় (এটি সাধারণত সম্পর্কিত হয়) ত্রুটি বার্তা)। টিপল নিজেই আরগস অ্যাট্রিবিউটে উপলব্ধ। "
ট্রেন্ট

2
আমি একদম বুঝতে পারি না। .messageবৈশিষ্ট্যটি এখানে কিছু করার একমাত্র কারণ হ'ল এই বৈশিষ্ট্যটি স্পষ্টভাবে মুদ্রিত। আপনি যদি ধরা এবং মুদ্রণ না করে ব্যতিক্রমটি বাড়িয়ে তুলেন তবে আপনি বৈশিষ্ট্যটি কোনও কার্যকর করতে দেখবেন না.message
ড্যানিয়েলস্যাঙ্ক

170

যদি আপনি কেবল অজগর 3.x সমর্থন করার পক্ষে যথেষ্ট ভাগ্যবান হন তবে এটি সত্যই সৌন্দর্যের একটি জিনিস হয়ে যায় :)

থেকে উত্থাপন

আমরা বাড়াতে ব্যবহার করে ব্যতিক্রমগুলি চেইন করতে পারি ।

try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception('Smelly socks') from e

এই ক্ষেত্রে, আপনার কলার যে ব্যতিক্রমটি ধরবে সে জায়গার লাইন নম্বর রয়েছে যেখানে আমরা আমাদের ব্যতিক্রম বাড়িয়ে তুলি।

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

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

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception('Smelly socks') from e
Exception: Smelly socks

লক্ষ্য করুন নীচের ব্যতিক্রমটিতে কেবল স্ট্যাকট্রেস রয়েছে যেখানে থেকে আমরা আমাদের ব্যতিক্রম উত্থাপন করেছি। আপনার কলার তারা এখনও __cause__যে ব্যতিক্রম ধরা আছে তার বৈশিষ্ট্যটি অ্যাক্সেসের মাধ্যমে মূল ব্যতিক্রমটি পেতে পারেন ।

with_traceback

অথবা আপনি_ট্র্যাসব্যাক ব্যবহার করতে পারেন ।

try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception('Smelly socks').with_traceback(e.__traceback__)

এই ফর্মটি ব্যবহার করে, আপনার কলার যে ব্যতিক্রমটি ধরবে সেটির ট্রেসব্যাকটি যেখানে আসল ত্রুটি ঘটেছে error

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception('Smelly socks').with_traceback(e.__traceback__)
  File "test.py", line 2, in <module>
    1 / 0
Exception: Smelly socks

লক্ষ্য করুন নীচের ব্যতিক্রমটিতে লাইন রয়েছে যেখানে আমরা অবৈধ বিভাগটি সম্পাদন করেছি এবং সেই রেখার পাশাপাশি যেখানে আমরা ব্যতিক্রমটিকে পুনরায় সাজাই।


1
অতিরিক্ত ট্রেসব্যাক ব্যতীত কোনও ব্যতিক্রমে কাস্টম বার্তা যুক্ত করা সম্ভব? উদাহরণস্বরূপ, raise Exception('Smelly socks') from eএর নিজস্ব একটি নতুন ট্রেসব্যাক প্রবর্তনের পরিবর্তে মূল ট্রেসব্যাকটিতে মন্তব্য হিসাবে কেবল "স্মেল মোজা" যুক্ত করতে সংশোধন করা যেতে পারে।
joelostblom

জোহান লন্ডবার্গের উত্তরটি থেকে আপনি এমন আচরণ পাবেন
বেন

3
এটা সত্যিই সুন্দর। ধন্যবাদ.
অ্যালানবেরি

3
একটি নতুন ব্যতিক্রম পুনরায় উত্থাপন বা নতুন বার্তা সহ চেইন উত্থাপন ব্যতিক্রম অনেক ক্ষেত্রে প্রয়োজনের চেয়ে আরও বিভ্রান্তি সৃষ্টি করে। নিজেই ব্যতিক্রমগুলি পরিচালনা করা জটিল। আরও ভাল কৌশল হ'ল আপনার বার্তাটি কেবল ব্যতিক্রম যুক্তির যুক্তিতে যুক্ত করা যদি সম্ভব হয় যেমন errargs + = ("বার্তা",) তে এবং ব্যতিক্রম বার্তাটি পুনরায় উত্থাপন করা। ট্রেসব্যাক আপনাকে লাইন নম্বরগুলিতে না নিয়ে যেতে পারে যেখানে ব্যতিক্রমটি ধরা পড়েছিল তবে এটি ব্যতিক্রমের ক্ষেত্রে নিশ্চিত হয়ে গেছে take
ব্যবহারকারী-গ্রহাণু

2
আপনি ক্লজ থেকে raise RuntimeError("Something bad happened") from None
কোনওটি

10
try:
    try:
        int('a')
    except ValueError as e:
        raise ValueError('There is a problem: {0}'.format(e))
except ValueError as err:
    print err

কপি করে প্রিন্ট:

There is a problem: invalid literal for int() with base 10: 'a'

1
আমি ভাবছিলাম যে আমি যা করার চেষ্টা করছি তার জন্য পাইথন রীতিমতো হ'ল, অন্য কোনও উদাহরণ উত্থাপন ব্যতীত ।
কিট

@ কিট - আমি এটিকে 'একটি ব্যতিক্রম পুনরুত্থান
সিম্পল_স্টমটস.ইচটিএমএল#

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

3
@ জোহান লন্ডবার্গ - raiseপরামিতি ছাড়াই পুনরায় উত্থাপন করছে। ওপি যদি কোনও বার্তা যুক্ত করতে চায় তবে তাকে নতুন ব্যতিক্রম বাড়াতে হবে এবং মূল ব্যতিক্রমের বার্তা / প্রকারটি পুনরায় ব্যবহার করতে পারে।
ইউরোমো

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

9

দেখে মনে হচ্ছে সমস্ত উত্তর ইয়ার্গ্স [0] এ তথ্য যুক্ত করছে, যার ফলে বিদ্যমান ত্রুটি বার্তাকে পরিবর্তন করা হবে। পরিবর্তে আরগস টিপল প্রসারিত করার কোনও খারাপ দিক রয়েছে কি? আমি মনে করি সম্ভাব্য বিপরীতটি হল, আপনি যে ক্ষেত্রে স্ট্রিংটিকে বিশ্লেষণ করা দরকার সেখানে মূল ত্রুটি বার্তাটি একা ছেড়ে দিতে পারেন; এবং যদি আপনার কাস্টম ত্রুটি পরিচালনার ফলে বেশ কয়েকটি বার্তা বা ত্রুটি কোড তৈরি হয় তবে আপনি ট্রেলেলে একাধিক উপাদান যুক্ত করতে পারেন, যেখানে ট্রেসব্যাক প্রোগ্রামিকভাবে পার্স করা হবে (যেমন কোনও সিস্টেম মনিটরিং সরঞ্জামের মাধ্যমে)।

## Approach #1, if the exception may not be derived from Exception and well-behaved:

def to_int(x):
    try:
        return int(x)
    except Exception as e:
        e.args = (e.args if e.args else tuple()) + ('Custom message',)
        raise

>>> to_int('12')
12

>>> to_int('12 monkeys')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')

অথবা

## Approach #2, if the exception is always derived from Exception and well-behaved:

def to_int(x):
    try:
        return int(x)
    except Exception as e:
        e.args += ('Custom message',)
        raise

>>> to_int('12')
12

>>> to_int('12 monkeys')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')

আপনি এই পদ্ধতির একটি খারাপ দিক দেখতে পাচ্ছেন?


আমার পুরানো উত্তর e.args [0] পরিবর্তন করে না।
জোহান লন্ডবার্গ

4

এই কোড টেমপ্লেটটি আপনাকে একটি কাস্টম বার্তা সহ একটি ব্যতিক্রম বাড়াতে অনুমতি দেবে।

try:
     raise ValueError
except ValueError as err:
    raise type(err)("my message")

3
এটি স্ট্যাক ট্রেস সংরক্ষণ করে না।

প্রশ্নকারী স্ট্যাক ট্রেস সংরক্ষণ করা হবে তা নির্দিষ্ট করে না।
shrewmouse

4

হয় আপনার ত্রুটি বার্তা ব্যবহার করে নতুন ব্যতিক্রম উত্থাপন

raise Exception('your error message')

অথবা

raise ValueError('your error message')

যে জায়গাটিতে আপনি এটি বাড়াতে চান বা তত্কালীন বার্তাটি 'থেকে' (পাইথন 3.x সমর্থিত কেবল) ব্যবহার করে বর্তমান ব্যতিক্রমের সাথে সংযুক্ত (প্রতিস্থাপন) করতে চান:

except ValueError as e:
  raise ValueError('your message') from e

থানেক্স, @ জিবার্গার, 'ই' এপ্রোথটি আসলে পাইথন ২.x দ্বারা সমর্থিত নয়
আলেক্সি আন্তোনেঙ্কো ১৯

3

আসল ট্রেসব্যাক সংরক্ষণের সময় পাইথন ২.7 এবং ৩.x এ ব্যতিক্রম বার্তাটি পরিবর্তন করতে আমি এই ফাংশনটি ব্যবহার করি। এটি প্রয়োজনsix

def reraise_modify(caught_exc, append_msg, prepend=False):
    """Append message to exception while preserving attributes.

    Preserves exception class, and exception traceback.

    Note:
        This function needs to be called inside an except because
        `sys.exc_info()` requires the exception context.

    Args:
        caught_exc(Exception): The caught exception object
        append_msg(str): The message to append to the caught exception
        prepend(bool): If True prepend the message to args instead of appending

    Returns:
        None

    Side Effects:
        Re-raises the exception with the preserved data / trace but
        modified message
    """
    ExceptClass = type(caught_exc)
    # Keep old traceback
    traceback = sys.exc_info()[2]
    if not caught_exc.args:
        # If no args, create our own tuple
        arg_list = [append_msg]
    else:
        # Take the last arg
        # If it is a string
        # append your message.
        # Otherwise append it to the
        # arg list(Not as pretty)
        arg_list = list(caught_exc.args[:-1])
        last_arg = caught_exc.args[-1]
        if isinstance(last_arg, str):
            if prepend:
                arg_list.append(append_msg + last_arg)
            else:
                arg_list.append(last_arg + append_msg)
        else:
            arg_list += [last_arg, append_msg]
    caught_exc.args = tuple(arg_list)
    six.reraise(ExceptClass,
                caught_exc,
                traceback)

3

পাইথন 3 অন্তর্নির্মিত ব্যতিক্রমগুলির strerrorক্ষেত্রটি রয়েছে:

except ValueError as err:
  err.strerror = "New error message"
  raise err

এটি কাজ করে না বলে মনে হচ্ছে। আপনি কি কিছুটা মিস করছেন?
মাসায়ো মিউজিক

2

বর্তমান উত্তরটি আমার পক্ষে ভাল কাজ করে না, যদি ব্যতিক্রমটি পুনরায় ধরা না হয় তবে সংযুক্তিযুক্ত বার্তাটি প্রদর্শিত হয় না।

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

try:
  raise ValueError("Original message")
except ValueError as err:
  t, v, tb = sys.exc_info()
  raise t, ValueError(err.message + " Appended Info"), tb

(আমি পাইথন ২.7 ব্যবহার করেছি, পাইথন 3 এ এটি ব্যবহার করে দেখিনি)


1

উপরের সমাধানগুলির কোনওটিই আমি যা চাইছিলাম ঠিক তেমন করে নি, যা ছিল ত্রুটি বার্তার প্রথম অংশে কিছু তথ্য যুক্ত করা অর্থাৎ আমি চাইছিলাম যে আমার ব্যবহারকারীরা আমার কাস্টম বার্তাটি প্রথম দেখুক।

এটি আমার পক্ষে কাজ করেছে:

exception_raised = False
try:
    do_something_that_might_raise_an_exception()
except ValueError as e:
    message = str(e)
    exception_raised = True

if exception_raised:
    message_to_prepend = "Custom text"
    raise ValueError(message_to_prepend + message)

0

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

একটি ব্যাতিক্রমটি এটি তৈরি করা আরগগুলি স্মরণ করে। আমি ধারণা করি এটি তাই যাতে আপনি ব্যতিক্রমটি সংশোধন করতে পারেন।

ফাংশনে reraiseআমরা ব্যতিক্রমগুলির মূল যুক্তিগুলি যে কোনও নতুন আর্গুমেন্ট যা আমরা চাই (যেমন একটি বার্তার মতো) দিয়ে রেখেছি end অবশেষে আমরা ট্রেস-ব্যাক ইতিহাস সংরক্ষণের সময় ব্যতিক্রমটি পুনরায় উত্থাপন করি।

def reraise(e, *args):
  '''re-raise an exception with extra arguments
  :param e: The exception to reraise
  :param args: Extra args to add to the exception
  '''

  # e.args is a tuple of arguments that the exception with instantiated with.
  #
  e.args = args + e.args

  # Recreate the expection and preserve the traceback info so thta we can see 
  # where this exception originated.
  #
  raise e.with_traceback(e.__traceback__)   


def bad():
  raise ValueError('bad')

def very():
  try:
    bad()
  except Exception as e:
    reraise(e, 'very')

def very_very():
  try:
    very()
  except Exception as e:
    reraise(e, 'very')

very_very()

আউটপুট

Traceback (most recent call last):
  File "main.py", line 35, in <module>
    very_very()
  File "main.py", line 30, in very_very
    reraise(e, 'very')
  File "main.py", line 15, in reraise
    raise e.with_traceback(e.__traceback__)
  File "main.py", line 28, in very_very
    very()
  File "main.py", line 24, in very
    reraise(e, 'very')
  File "main.py", line 15, in reraise
    raise e.with_traceback(e.__traceback__)
  File "main.py", line 22, in very
    bad()
  File "main.py", line 18, in bad
    raise ValueError('bad')
ValueError: ('very', 'very', 'bad')

-3

আপনি যদি ত্রুটি প্রকারটি কাস্টম করতে চান তবে একটি সাধারণ জিনিসটি আপনি করতে পারেন ভ্যালুআরারের উপর ভিত্তি করে একটি ত্রুটি শ্রেণি নির্ধারণ করা।


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