python - पायथन में stderr को कैसे मुद्रित करें?




printing zen (10)

मैं stderr को मुद्रित करने के कम से कम तीन तरीकों से आया है:

 import sys

 print >> sys.stderr, 'spam'

 sys.stderr.write('spam\n')

 from __future__ import print_function
 print('spam', file=sys.stderr)

ऐसा लगता है कि पाइथन # 13 † के ज़ेन का विरोधाभास है, तो ऐसा करने का पसंदीदा तरीका क्या है? क्या एक तरफ या दूसरे के लिए कोई फायदे या नुकसान हैं?

एक होना चाहिए - और अधिमानतः केवल एक - इसे करने का स्पष्ट तरीका।


सवाल का जवाब है: अजगर में stderr मुद्रित करने के लिए अलग-अलग तरीके हैं लेकिन यह 1 पर निर्भर करता है।) जो अजगर संस्करण हम उपयोग कर रहे हैं 2.) हम कौन सा सटीक आउटपुट चाहते हैं।

प्रिंट और स्टीडर के लेखन समारोह के बीच भिन्नता: stderr : stderr (मानक त्रुटि) पाइप है जो प्रत्येक यूनिक्स / लिनक्स सिस्टम में बनाया गया है, जब आपका प्रोग्राम क्रैश हो जाता है और डिबगिंग जानकारी प्रिंट करता है (जैसे पायथन में ट्रेसबैक), यह stderr पर जाता है पाइप।

प्रिंट : प्रिंट एक रैपर है जो इनपुट को स्वरूपित करता है (इनपुट अंत में तर्क और अंत में नई लाइन के बीच की जगह है) और फिर किसी दिए गए ऑब्जेक्ट के लेखन फ़ंक्शन को कॉल करता है, डिफ़ॉल्ट रूप से दिया गया ऑब्जेक्ट sys.stdout है, लेकिन हम कर सकते हैं एक फ़ाइल पास करें यानी हम एक फाइल में भी इनपुट प्रिंट कर सकते हैं।

Python2: अगर हम python2 का उपयोग कर रहे हैं तो

>>> import sys
>>> print "hi"
hi
>>> print("hi")
hi
>>> print >> sys.stderr.write("hi")
hi

Python2 पिछला कॉमा पाइथन 3 में पैरामीटर बन गया है, इसलिए यदि हम प्रिंट के बाद नई लाइन से बचने के लिए पिछली कॉमा का उपयोग करते हैं, तो यह Python3 में प्रिंट ('टेक्स्ट टू प्रिंट', एंड = '') जैसा दिखता है जो Python2 के तहत एक वाक्यविन्यास त्रुटि है ।

http://python3porting.com/noconv.html

यदि हम python3 में sceario से ऊपर की जाँच करते हैं:

>>> import sys
>>> print("hi")
hi

पायथन 2.6 के तहत फ़ंक्शन में प्रिंट करने के लिए भविष्य का आयात होता है। तो किसी भी वाक्यविन्यास त्रुटियों और अन्य मतभेदों से बचने के लिए हमें किसी भी फाइल को शुरू करना चाहिए जहां हम भविष्य के आयात print_function से प्रिंट () का उपयोग करते हैं। भविष्य का आयात केवल पायथन 2.6 और बाद में काम करता है, इसलिए पाइथन 2.5 और इससे पहले आपके पास दो विकल्प हैं। आप या तो अधिक जटिल प्रिंट को कुछ आसान में परिवर्तित कर सकते हैं, या आप एक अलग प्रिंट फ़ंक्शन का उपयोग कर सकते हैं जो कि Python2 और Python3 दोनों के अंतर्गत काम करता है।

>>> from __future__ import print_function
>>> 
>>> def printex(*args, **kwargs):
...     print(*args, file=sys.stderr, **kwargs)
... 
>>> printex("hii")
hii
>>>

केस: ध्यान दें कि sys.stderr.write () या sys.stdout.write () (stdout (मानक आउटपुट) एक पाइप है जो प्रत्येक यूनिक्स / लिनक्स सिस्टम में बनाया गया है) प्रिंट के लिए प्रतिस्थापन नहीं है, लेकिन हां हम इसे कुछ मामलों में एक विकल्प के रूप में उपयोग कर सकते हैं। प्रिंट एक रैपर है जो अंत में अंतरिक्ष और नई लाइन के साथ इनपुट लपेटता है और लिखने के लिए लेखन कार्य का उपयोग करता है। यही कारण है sys.stderr.write () तेज है।

नोट: हम लॉगिंग का उपयोग करके ट्रेस और डिबग भी कर सकते हैं

#test.py
import logging
logging.info('This is the existing protocol.')
FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
logging.basicConfig(format=FORMAT)
d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
logging.warning("Protocol problem: %s", "connection reset", extra=d)

https://docs.python.org/2/library/logging.html#logger-objects


किसी ने अभी तक logging का उल्लेख नहीं किया है, लेकिन लॉगिंग विशेष रूप से त्रुटि संदेशों को संवाद करने के लिए बनाई गई थी। डिफ़ॉल्ट रूप से यह stderr को लिखने के लिए सेट अप किया गया है। यह स्क्रिप्ट:

# foo.py
import logging
logging.basicConfig(format='%(message)s')

logging.warn('I print to stderr by default')
logging.info('For this you must change the level and add a handler.')
print('hello world')

कमांड लाइन पर चलने पर निम्न परिणाम होता है:

$ python3 foo.py > bar.txt
I print to stderr by default

(और bar.txt में 'हैलो वर्ल्ड' है)


मैं अजगर 3.4.3 में काम कर रहा हूँ। मैं थोड़ा टाइपिंग काट रहा हूं जो दिखाता है कि मैं यहां कैसे आया:

[18:19 [email protected] pexpect]$ python3
>>> import sys
>>> print("testing", file=sys.stderr)
testing
>>>
[18:19 [email protected] pexpect]$ 

काम किया? एक फ़ाइल में stderr पुनर्निर्देशित करने का प्रयास करें और देखें कि क्या होता है:

[18:22 [email protected] pexpect]$ python3 2> /tmp/test.txt
>>> import sys
>>> print("testing", file=sys.stderr)
>>> [18:22 [email protected] pexpect]$
[18:22 [email protected] pexpect]$ cat /tmp/test.txt
Python 3.4.3 (default, May  5 2015, 17:58:45)
[GCC 4.9.2] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
testing

[18:22 [email protected] pexpect]$

खैर, इस तथ्य से अलग कि पाइथन आपको थोड़ा परिचय देता है जिसे आपको stderr में फिसल दिया गया है (यह और कहां जाएगा?), यह काम करता है।


मैं कहूंगा कि आपका पहला दृष्टिकोण:

print >> sys.stderr, 'spam' 

"इसे करने का एक स्पष्ट तरीका" है अन्य लोग नियम # 1 को संतुष्ट नहीं करते हैं ("सुंदर बदसूरत से बेहतर है।")


मैंने पाया कि यह केवल एक छोटा + लचीला + पोर्टेबल + पठनीय है:

from __future__ import print_function
import sys

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

फ़ंक्शन eprint का उपयोग मानक print फ़ंक्शन के समान ही किया जा सकता है:

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz

यदि आप एक साधारण परीक्षण करते हैं:

import time
import sys

def run1(runs):
    x = 0
    cur = time.time()
    while x < runs:
        x += 1
        print >> sys.stderr, 'X'
    elapsed = (time.time()-cur)
    return elapsed

def run2(runs):
    x = 0
    cur = time.time()
    while x < runs:
        x += 1
        sys.stderr.write('X\n')
        sys.stderr.flush()
    elapsed = (time.time()-cur)
    return elapsed

def compare(runs):
    sum1, sum2 = 0, 0
    x = 0
    while x < runs:
        x += 1
        sum1 += run1(runs)
        sum2 += run2(runs)
    return sum1, sum2

if __name__ == '__main__':
    s1, s2 = compare(1000)
    print "Using (print >> sys.stderr, 'X'): %s" %(s1)
    print "Using (sys.stderr.write('X'),sys.stderr.flush()):%s" %(s2)
    print "Ratio: %f" %(float(s1) / float(s2))

आप पाएंगे कि sys.stderr.write () लगातार 1.81 गुना तेज है!


यह मानक प्रिंट फ़ंक्शन की नकल करेगा लेकिन stderr पर आउटपुट होगा

def print_err(*args):
    sys.stderr.write(' '.join(map(str,args)) + '\n')

print >> sys.stderr में चला गया है। http://docs.python.org/3.0/whatsnew/3.0.html कहता है:

Old: print >>sys.stderr, "fatal error"
New: print("fatal error", file=sys.stderr)

दुर्भाग्य से, यह काफी बदसूरत है। वैकल्पिक रूप से, उपयोग करें

sys.stderr.write("fatal error\n")

लेकिन ध्यान दें कि print लिए 1: 1 प्रतिस्थापन नहीं है।


पायथन 2 के लिए मेरी पसंद है: print >> sys.stderr, 'spam' क्योंकि आप स्ट्रिंग में कनवर्ट किए बिना सूचियों / डिक्ट आदि को प्रिंट कर सकते हैं। print >> sys.stderr, {'spam': 'spam'} बजाय: sys.stderr.write(str({'spam': 'spam'}))


संपादित करें हिंड-दृष्टि में, मुझे लगता है कि बदलते sys.stderr के साथ संभावित भ्रम और अद्यतन व्यवहार को नहीं देखकर यह जवाब केवल एक साधारण कार्य के रूप में उतना अच्छा नहीं है जितना कि दूसरों ने इंगित किया है।

आंशिक का उपयोग केवल आपको कोड की 1 पंक्ति बचाता है। संभावित भ्रम कोड की 1 पंक्ति को बचाने के लायक नहीं है।

मूल

इसे और भी आसान बनाने के लिए, यहां एक संस्करण है जो 'आंशिक' का उपयोग करता है, जो फ़ंक्शन को लपेटने में एक बड़ी सहायता है।

from __future__ import print_function
import sys
from functools import partial

error = partial(print, file=sys.stderr)

फिर आप इसका इस्तेमाल करते हैं

error('An error occured!')

आप यह जांच सकते हैं कि यह stderr पर प्रिंट कर रहा है और निम्नलिखित नहीं कर रहा है ( http://coreygoldberg.blogspot.com.au/2009/05/python-redirect-or-turn-off-stdout-and.html से अधिक सवारी कोड http://coreygoldberg.blogspot.com.au/2009/05/python-redirect-or-turn-off-stdout-and.html ):

# over-ride stderr to prove that this function works.
class NullDevice():
    def write(self, s):
        pass
sys.stderr = NullDevice()

# we must import print error AFTER we've removed the null device because
# it has been assigned and will not be re-evaluated.
# assume error function is in print_error.py
from print_error import error

# no message should be printed
error("You won't see this error!")

इसका नकारात्मक भाग आंशिक रूप से सृजन के समय लिपटे फ़ंक्शन में sys.stderr का मान निर्दिष्ट करता है। जिसका अर्थ है, यदि आप बाद में stderr को रीडायरेक्ट करते हैं तो यह इस फ़ंक्शन को प्रभावित नहीं करेगा। यदि आप stderr को रीडायरेक्ट करने की योजना बना रहे हैं, तो इस पृष्ठ पर aaguirre द्वारा उल्लिखित ** kwargs विधि का उपयोग करें।





zen