मैं अब तक सफलता के बिना पाइथन आंतरिक (और एक दोस्त के साथ गड़बड़) के बारे में और जानने के लिए एक अपवाद के प्रिंट करने योग्य आउटपुट को मूर्खतापूर्ण संदेश में बदलने का एक तरीका खोज रहा हूं।

निम्नलिखित कोड पर विचार करें

try:
   x # is not defined
except NameError as exc:
   print(exc)

कोड name 'x' is not defined आउटपुट करेगा

मैं उस आउटपुट को the name 'x' you suggested is not yet defined, my lord. Improve your coding skills में बदलना चाहता हूं।

अब तक, मैं समझ गया था कि आप __builtins__ को नहीं बदल सकते क्योंकि वे C कोड के रूप में "बेक्ड इन" हैं, जब तक कि:

  1. आप वर्जितफ्रूट.कर्स विधि का उपयोग करते हैं जो किसी भी वस्तु के गुणों को जोड़ता/बदलता है
  2. आप किसी ऑब्जेक्ट के शब्दकोशों को मैन्युअल रूप से ओवरराइड करते हैं

मैंने दोनों समाधानों की कोशिश की है, लेकिन सफलता के बिना:

निषिद्ध फल समाधान:

from forbiddenfruit import curse

curse(BaseException, 'repr', lambda self: print("Test message for repr"))
curse(BaseException, 'str', lambda self: print("Test message for str"))

try:
    x
except NameError as exc:
    print(exc.str()) # Works, shows test message
    print(exc.repr()) # Works, shows test message
    print(repr(exc)) # Does not work, shows real message
    print(str(exc)) # Does not work, shows real message
    print(exc) # Does not work, shows real message

शब्दकोश अधिभावी समाधान:

import gc

underlying_dict = gc.get_referents(BaseException.__dict__)[0]
underlying_dict["__repr__"] = lambda self: print("test message for repr")
underlying_dict["__str__"] = lambda self: print("test message for str")
underlying_dict["args"] = 'I am an argument list'

try:
    x
except NameError as exc:
    print(exc.__str__()) # Works, shows test message
    print(exc.__repr__()) # Works, shows test message
    print(repr(exc)) # Does not work, shows real message
    print(str(exc)) # Does not work, shows real message
    print(exc) # Does not work, shows real message

AFAIK, print(exc) का उपयोग करके __repr__ या __str__ पर निर्भर होना चाहिए, लेकिन यह प्रिंट फ़ंक्शन की तरह लगता है कुछ और का उपयोग करता है, जो मुझे BaseException के सभी गुणों को print(dir(BaseException)) के माध्यम से पढ़ने पर भी नहीं मिल रहा है। क्या कोई मुझे इस बात की जानकारी दे सकता है कि कृपया इस मामले में प्रिंट क्या उपयोग करता है?

[संपादित करें]

थोड़ा और संदर्भ जोड़ने के लिए:

जिस समस्या को मैं हल करने का प्रयास कर रहा हूं, वह एक प्रोग्रामर मित्र के साथ खिलवाड़ करने के लिए एक मजाक के रूप में शुरू हुई, लेकिन अब मेरे लिए अजगर के आंतरिक को और अधिक समझने की चुनौती बन गई है।

कोई वास्तविक व्यावसायिक समस्या नहीं है जिसे मैं हल करने का प्रयास कर रहा हूं, मैं केवल पायथन में चीजों की गहरी समझ प्राप्त करना चाहता हूं। मैं काफी हैरान हूं कि print(exc) वास्तव में BaseException.__repr__ या __str__ का उपयोग नहीं करेगा।

[/ संपादित करें]

8
Orsiris de Jong 30 अक्टूबर 2020, 18:13

4 जवाब

सबसे बढ़िया उत्तर

मैं आपके द्वारा वर्णित व्यवहार की व्याख्या करूंगा:

  • exc.__repr__()

यह सिर्फ आपके लैम्ब्डा फ़ंक्शन को कॉल करेगा और अपेक्षित स्ट्रिंग लौटाएगा। बीटीडब्ल्यू आपको स्ट्रिंग वापस करनी चाहिए, इसे अपने लैम्ब्डा फ़ंक्शंस में प्रिंट नहीं करना चाहिए।

  • print(repr(exc))

अब, यह CPython में एक अलग मार्ग पर जा रहा है और आप इसे GDB सत्र में देख सकते हैं, यह कुछ इस तरह है:

Python/bltinmodule.c:builtin_repr Objects/object.c:PyObject_Repr को कॉल करेगा - इस फ़ंक्शन को PyObject *v एकमात्र पैरामीटर के रूप में मिलता है जिसका उपयोग वह एक फ़ंक्शन को प्राप्त करने और कॉल करने के लिए करेगा जो अंतर्निहित फ़ंक्शन को लागू करता है repr(), इस मामले में BaseException_repr। यह फ़ंक्शन args संरचना फ़ील्ड के मान के आधार पर त्रुटि संदेश को प्रारूपित करेगा:

(gdb) p ((PyBaseExceptionObject *) self)->args 
$188 = ("name 'x' is not defined",)

args मान Python/ceval.c:format_exc_check_arg में उसी फ़ाइल में NAME_ERROR_MSG मैक्रो सेट के आधार पर सेट किया गया है।

अपडेट करें: सूर्य ८ नवंबर २०:१९:२६ यूटीसी २०२०

test.py:

import sys
import dis


def main():
    try:
        x
    except NameError as exc:
        tb = sys.exc_info()[2]
        frame, i = tb.tb_frame, tb.tb_lasti
        code = frame.f_code
        arg = code.co_code[i + 1]
        name = code.co_names[arg]
        print(name)


if __name__ == '__main__':
    main()

परीक्षण:

# python test.py
x

नोट:

मैं PyCon 2016 का यह वीडियो देखने की भी सलाह दूंगा।

1
marc_s 9 मई 2021, 22:53

आप जो पूछ रहे हैं उसे करने के लिए पायथन कोई तरीका प्रदान नहीं करता है। ये ऑब्जेक्ट C में लिखे गए हैं और संशोधन के लिए उपलब्ध नहीं हैं।

यदि आप आउटपुट को संशोधित करना चाहते हैं तो आपको या तो NameError का संदर्भ देना होगा, जो आप चाहते हैं उसे निकालने और प्रिंट करने के लिए NameError आउटपुट को पार्स करें या अपवाद खंड में e.args को संशोधित करें (x की हार्ड कोडिंग की आवश्यकता है)।

एक अन्य विकल्प यह होगा कि x के मान को कोई नहीं (या जो भी डिफ़ॉल्ट आप पसंद करते हैं) को डिफ़ॉल्ट करें और या तो उस मान के आधार पर अपना अपवाद या तर्क बढ़ाएं।

ऐसा कहने के साथ, मैं यह समझना चाहता हूं कि क्यों आप ऐसा करना चाहते हैं / जिसे आप हल करने का प्रयास कर रहे हैं-क्योंकि आपकी पहली ऑर्डर समस्या में एक अच्छी तरह से परिभाषित पाइथोनिक सम्मेलन हो सकता है।

0
pygeek 2 नवम्बर 2020, 22:29

परिचय

मैं इस बारे में अधिक आलोचनात्मक दृष्टिकोण के साथ जाऊंगा कि आप वह क्यों करना चाहते हैं जो आप करना चाहते हैं।

पायथन आपको विशिष्ट अपवादों को संभालने की क्षमता प्रदान करता है। इसका मतलब है कि यदि आपको कोई व्यावसायिक समस्या थी, तो आप एक विशेष अपवाद वर्ग का उपयोग करेंगे और उस विशिष्ट मामले के लिए एक कस्टम संदेश प्रदान करेंगे। अब, इस पैराग्राफ को याद रखें और आगे बढ़ते हैं, मैं इसका उल्लेख बाद में करूंगा।


टीएल; डीआर

अब, ऊपर-नीचे चलते हैं:

except Exception के साथ सभी प्रकार की त्रुटियों को पकड़ना आम तौर पर एक अच्छा विचार नहीं है यदि आप पकड़ना चाहते हैं तो मान लें कि एक चर नाम त्रुटि है। आप इसके बजाय except NameError का उपयोग करेंगे। आप इसमें वास्तव में बहुत कुछ नहीं जोड़ेंगे इसलिए इसमें एक डिफ़ॉल्ट संदेश था जो इस मुद्दे का पूरी तरह से वर्णन करता है। तो यह माना जाता है कि आप इसका उपयोग वैसे ही करेंगे जैसे यह दिया गया है। इन्हें ठोस अपवाद कहा जाता है।

अब, अपने विशिष्ट मामले के साथ उपनाम as exc पर ध्यान दें। उपनाम का उपयोग करके आप डिफ़ॉल्ट संदेश सहित अपवाद ऑब्जेक्ट को दिए गए तर्कों तक पहुंच सकते हैं।

try:
   x # is not defined
except NameError as exc:
   print(exc.args)

उस कोड को चलाएँ (मैंने इसे app.py में डाला है) और आप देखेंगे:

$ python app.py
("name 'x' is not defined",)

ये args एक श्रृंखला (सूची, या इस मामले में अपरिवर्तनीय सूची जो एक टपल है) के रूप में अपवाद के लिए पास की जाती हैं।

यह अपवादों के निर्माणकर्ताओं (__init__) को आसानी से तर्क पारित करने की संभावना के विचार की ओर ले जाता है। आपके मामले में "name 'x' is not defined" को तर्क के रूप में पारित किया गया था।

आप केवल एक कस्टम संदेश प्रदान करके अपनी समस्या को हल करने के लिए अपने लाभ के लिए इसका उपयोग कर सकते हैं, जैसे:

try:
   x # is not defined
except NameError as exc:
   your_custom_message = "the name 'x' you suggested is not yet defined, my lord. Improve your coding skills"
   # Now, you can handle it based on your requirement:
   #  print(your_custom_message)
   #  print(NameError(your_custom_message))
   #  raise NameError(your_custom_message)
   #  raise NameError(your_custom_message) from exc

आउटपुट अब वह है जिसे आप हासिल करना चाहते थे।

$ python app.py
the name 'x' you suggested is not yet defined, my lord. Improve your coding skills

पहला पैराग्राफ याद रखें जब मैंने कहा था कि मैं इसे बाद में देखूंगा? मैंने एक विशिष्ट मामले के लिए एक कस्टम संदेश प्रदान करने का उल्लेख किया है। यदि आप अपने उत्पाद के लिए प्रासंगिक विशिष्ट चर के लिए नाम त्रुटियों को संभालना चाहते हैं, तो आप अपनी खुद की लाइब्रेरी बनाते हैं, तो आप मानते हैं कि आपके उपयोगकर्ता आपके कोड का उपयोग करेंगे जो उस NameError अपवाद को बढ़ा सकता है। वे इसे except Exception as exc या except NameError as exc के साथ पकड़ लेंगे। और जब वे print(exc) करते हैं, तो वे अब आपका संदेश देखेंगे।


सारांश

मुझे आशा है कि यह आपको समझ में आता है, बस एक कस्टम संदेश प्रदान करें और इसे NameError के तर्क के रूप में पास करें या बस इसे प्रिंट करें। आईएमओ, इसे ठीक से सीखना बेहतर है कि आप जो उपयोग करते हैं उसका उपयोग क्यों करेंगे।

3
Eli Halych 8 नवम्बर 2020, 17:39

इस तरह की त्रुटियों को दुभाषिया में हार्ड-कोड किया जाता है (सीपीथन के मामले में, वैसे भी, जो कि आप जो उपयोग कर रहे हैं उसकी सबसे अधिक संभावना है)। आप पायथन के भीतर से ही छपे संदेश को नहीं बदल पाएंगे।

जब CPython दुभाषिया किसी नाम को ढूँढ़ने का प्रयास करता है तो वह C स्रोत कोड यहाँ पाया जा सकता है: https://github.com/python/cpython/blob/master/Python/ceval.c#L2602। यदि आप नाम लुकअप विफल होने पर छपे त्रुटि संदेश को बदलना चाहते हैं, तो आपको यह पंक्ति उसी फ़ाइल में:

#define NAME_ERROR_MSG \
    "name '%.200s' is not defined"

संशोधित स्रोत कोड को संकलित करने से एक पायथन दुभाषिया प्राप्त होगा जो परिभाषित नहीं किए गए नाम का सामना करते समय आपके कस्टम त्रुटि संदेश को प्रिंट करता है।

2
CyanoKobalamyne 8 नवम्बर 2020, 03:07