python - त्वरित डिबगिंग के लिए गणना आउटपुट के साथ शाब्दिक रूप से मुद्रित अभिव्यक्ति को प्रिंट करने के लिए प्रिंट() विधि




debugging logging (6)

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

उदाहरण के लिए, निम्नलिखित कोड के लिए:

print(42 + 42)
print(type(list))
print(datetime.now())

मौजूदा उत्पादन:

84
<class 'type'>
2019-08-15 22:43:57.805861

अपेक्षित उत्पादन:

42 + 42 : 84
type(list) : <class 'type'>
datetime.now() : 2019-08-15 22:43:57.805861

वर्तमान में, वही अभिव्यक्ति स्ट्रिंग जोड़कर प्राप्त किया जा सकता है, (इतना सुंदर नहीं imho और DRY सिद्धांत का उल्लंघन करता है)।

print("42 + 42 : ", 42 + 42)
print("type(list) : ", type(list))
print("datetime.now() : ", datetime.now())

मैंने बिलिन प्रिंट को ओवरराइड करने की कोशिश की है, लेकिन सफलता के बिना:

import builtins
def print(*args, **kwargs):
    return builtins.print(*args, **kwargs)  # passed expression isn't available here as string!

क्या इसको हासिल करने के लिए कोई रास्ता है? धन्यवाद!


f-str Python 3.8 (वर्तमान में बीटा) में कुछ इस तरह का समर्थन करेगा।

docs :

एक f-string जैसे f '{expr =}' एक्सप्रेशन के टेक्स्ट के बराबर होगा, एक बराबर साइन, फिर मूल्यांकित एक्सप्रेशन का प्रतिनिधित्व। उदाहरण के लिए:

>>> user = 'eric_idle'
>>> member_since = date(1975, 7, 31)
>>> f'{user=} {member_since=}'
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"

सामान्य एफ-स्ट्रिंग प्रारूप निर्दिष्टकर्ता अभिव्यक्ति के परिणाम को प्रदर्शित करने पर अधिक नियंत्रण की अनुमति देते हैं:

>>> delta = date.today() - member_since
>>> f'{user=!s}  {delta.days=:,d}'
'user=eric_idle  delta.days=16,075'

= निर्दिष्टकर्ता पूरी अभिव्यक्ति प्रदर्शित करेगा ताकि गणना दिखाई जा सके:

>>> print(f'{theta=}  {cos(radians(theta))=:.3f}')
theta=30  cos(radians(theta))=0.866

आप https://github.com/cool-RR/PySnooper उपयोग कर सकते हैं

In [1]: from datetime import datetime                                                                                                                                                                                                         

In [2]: import pysnooper                                                                                                                                                                                                                      

In [3]: @pysnooper.snoop() 
   ...: def output(): 
   ...:     print(42 + 42) 
   ...:     print(type(list)) 
   ...:     print(datetime.now()) 
   ...:                                                                                                                                                                                                                                       

In [4]: output()                                                                                                                                                                                                                              
Source path:... <ipython-input-3-d5732f8e9c36>
22:14:08.934915 call         2 def output():
22:14:08.935031 line         3     print(42 + 42)
84
22:14:08.935061 line         4     print(type(list))
<class 'type'>
22:14:08.935083 line         5     print(datetime.now())
2019-08-25 22:14:08.935100
22:14:08.935109 return       5     print(datetime.now())
Return value:.. None

आप कॉल करने वाले से सोर्स लाइन ( code_context ) प्राप्त करने के लिए मॉड्यूल inspect का उपयोग कर सकते हैं:

from inspect import getframeinfo, currentframe


def vprint(value):
    caller = currentframe().f_back
    info = getframeinfo(caller)
    label = ''.join(info.code_context).strip()
    label = label.replace('vprint(', '')[:-1].strip()
    print(label, '=', value)


>>> vprint(12 + 3)
12 + 3 = 15
>>> vprint(type(list))
type(list) = <type 'type'>
>>> vprint(lambda x: x + 1)
lambda x: x + 1 = <function <lambda> at 0x7f93c104b9b0>

केवल सिंगल-लाइन मूल्यांकन के लिए अच्छी तरह से काम करेगा। चूंकि code_context केवल निष्पादित लाइन देता है (और संपूर्ण निर्देश नहीं), ऐसा हो सकता है:

>>> vprint([''] +
...:     ['a', 'b'])
['a', 'b'] = ['', 'a', 'b']
>>> vprint(math.log(
...:   2 * math.pi))
2 * math.pi) = 1.83787706641

नोट: ब्रेकिंग लाइन with \ फिक्सेस (इंडेंटेशन अभी भी अजीब लगेगा):

>>> vprint(math.log( \
...:   2 * math.pi))
math.log(   2 * math.pi) = 1.83787706641

आम तौर पर मुझे लगता है कि अगर आप अपने आप को eval का उपयोग करते हुए पाते हैं, तो शायद एक बेहतर तरीका है जो आप करने की कोशिश कर रहे हैं, लेकिन:

for statement in ["42 + 42", "type(list)", "datetime.now()"]:
    print("{} : {}".format(statement, eval(statement))

जब आप प्रिंट विधि को कॉल करते हैं, तो पास किए गए तर्कों का मूल्यांकन प्रिंट विधि द्वारा नहीं किया जाता है, उन्हें तर्क के रूप में प्रिंट विधि में पास करने से पहले मूल्यांकन किया जाता है।

print(42 + 42)  => print(84)
print(type(list)) => print(<type 'type'>)
print(datetime.now()) => print(datetime.datetime(2019, 8, 15, 23, 9, 50, 619157))

आंतरिक रूप से प्रिंट विधि बस दिए गए ऑब्जेक्ट को __str __ () द्वारा पास की गई वस्तु की विधि से परिवर्तित करती है


बस ट्रेसबैक का उपयोग करें और कॉल तर्क के लिए खोज करें।

इस समाधान का लाभ यह है कि आपको अभिव्यक्ति को कोष्ठक में नहीं रखना है।

import re
import traceback
def prnt_expression(expression):
    for s in traceback.format_stack():
        match = re.search('prnt_expression\((.*)\)', s)
        if match:
            expression_string = match.group(1)
            break
    print(f'{expression_string} : {expression}')

इसे इस तरह से कॉल करें:

prnt_expression(42 + 42)




logging