web-dev-qa-db-ja.com

Pythonで標準エラーに出力するにはどうすればいいですか?

Stderrに書き込む方法はいくつかあります。

 # Note: this first one does not work in Python 3
 print >> sys.stderr, "spam"

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

 os.write(2, b"spam\n")

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

それは矛盾しているようです Python#13の禅  それでは、ここでの違いは何ですか、また一方で他に利点や欠点がありますか?どちらの方法を使うべきですか?

それを行うには、明白な方法が1つ(できれば1つだけ)あるべきです。

1133
wim

私はこれが唯一の短い+柔軟な+移植可能な+読み取り可能なものであることがわかりました。

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
971
MarcH
import sys
sys.stderr.write()

私の選択は、もっと読みやすく、あなたがやろうとしていることとバージョン間で移植性があることを正確に言っていることです。

編集:「Pythonic」であることは、読みやすさとパフォーマンスに関して私には3番目に考えられます。Pythonでは、コードの80%がPythonicになります。リストの内包表記は、それほど頻繁には使用されない「読みやすい」ものです。

475
Mike Ramirez

Python 2の場合 私の選択はprint >> sys.stderr, 'spam'文字列に変換せずに単純にリストや辞書などを印刷できるからです。 sys.stderr.write(str({'spam': 'spam'}))の代わりにprint >> sys.stderr, {'spam': 'spam'}

130

print >> sys.stderrはPython 3ではなくなりました。 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")

しかし、writeprintの1:1の置き換えではありません。

114
Joachim W

まだ誰もloggingに言及していませんが、ロギングはエラーメッセージを伝えるために特別に作成されました。デフォルトではstderrに書き込むように設定されています。このスクリプト:

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

logging.warning('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 には「hello world」が含まれます)

(注、logging.warn非推奨となりました 、代わりにlogging.warningを使用してください)

87
slushy

私はあなたの最初のアプローチと言うでしょう:

print >> sys.stderr, 'spam' 

「……明らかにやり方)他の人はルール#1を満たしていません(「美しいのは醜いより優れています」)

33
Carl F.

私はPython 3を使って次のことをしました。

from sys import stderr

def print_err(*args, **kwargs):
    print(*args, file=stderr, **kwargs)

これで、キャリッジリターンを避けるために、たとえばキーワード引数を追加できます。

print_err("Error: end of the file reached. The Word ", end='')
print_err(Word, "was not found")
30
aaguirre

これは標準のprint関数に似ていますが、stderrに出力されます。

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

_ edit _ 後になると、sys.stderrを変更しても動作が更新されないので混乱する可能性があるため、他の人が指摘した単純な関数を使用するだけでは不十分です。

パーシャルのみを使用すると、1行のコードを節約できます。潜在的な混乱は1行のコードを保存する価値がありません。

オリジナル

さらに簡単にするために、これは 'partial'を使用するバージョンです。これは、関数をラップするのに非常に役立ちます。

from __future__ import print_function
import sys
from functools import partial

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

あなたはそれをそれのように使う

error('An error occured!')

次のコードを実行することで、標準出力ではなく標準出力に出力されていることを確認できます( 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メソッドを使用してください。

17
Rebs

同じことが標準出力にも当てはまります。

print 'spam'
sys.stdout.write('spam\n')

他の答えで述べたように、printは(例えばデバッグ情報を印刷するために)もっと便利なきれいなインターフェースを提供しますが、writeは速くて出力をフォーマットしなければならない時にももっと便利になります。ある意味で正確に。保守性も考慮します。

  1. あとでstdout/stderrと通常のファイルを切り替えることにするかもしれません。

  2. Python 3では、print()の構文が変更されたため、両方のバージョンをサポートする必要がある場合は、write()の方が良い場合があります。

7
Seppo Enarvi

私はPython 3.4.3で働いています。私がここに来た方法を示す少しタイピングを切り取っています:

[18:19 jsilverman@JSILVERMAN-LT7 pexpect]$ python3
>>> import sys
>>> print("testing", file=sys.stderr)
testing
>>>
[18:19 jsilverman@JSILVERMAN-LT7 pexpect]$ 

うまくいきましたか。 stderrをファイルにリダイレクトして何が起こるのか見てみましょう:

[18:22 jsilverman@JSILVERMAN-LT7 pexpect]$ python3 2> /tmp/test.txt
>>> import sys
>>> print("testing", file=sys.stderr)
>>> [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$
[18:22 jsilverman@JSILVERMAN-LT7 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 jsilverman@JSILVERMAN-LT7 pexpect]$

さて、pythonがあなたに与えるちょっとした紹介がstderr(他にどこに行くのでしょうか)に転じたという事実は別として、それはうまくいきます。

6
user1928764

簡単なテストをするなら:

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 __== '__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 倍速くなることがわかります。

3
ThePracticalOne

Python 3では、 print()を使うことができます:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

ほとんど箱から出して:

import sys
print("Hello, world!", file=sys.stderr)

または

from sys import stderr
print("Hello, world!", file=stderr)

これは簡単で、sys.stderr以外に何かを含める必要はありません。

3

質問への答えは次のとおりです。Pythonでstderrを印刷するには別の方法がありますが、それは1)使用しているpythonのバージョン、2)正確な出力に依存します。

Printとstderrの書き込み関数の違いは: stderr :stderr(標準エラー)は、プログラムがクラッシュして(Pythonのトレースバックのように)デバッグ情報を出力するときに、すべてのUNIX/Linuxシステムに組み込まれるパイプです。それは標準エラー出力パイプに行きます。

print :printは入力をフォーマットするラッパーで(入力は引数と最後の改行の間のスペースです)、それから与えられたオブジェクトのwrite関数を呼び出します。与えられたオブジェクトはデフォルトでsysです。 .stdoutですが、ファイルを渡すこともできます。つまり、入力をファイルに出力することもできます。

Python2:もしpython2を使っているのであれば

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

Python2の末尾のカンマはPython 3ではパラメータになっているので、印刷後の改行を避けるために末尾のカンマを使用すると、Python 3ではこれはprint( 'Text to print'、end = '')のようになります。 。

http://python3porting.com/noconv.html

上記のscearioをpython3でチェックしたとします。

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

Python 2.6では、関数に出力するための future インポートがあります。そのため、構文エラーやその他の違いを避けるために、print()を使用するすべてのファイルをfrom future import print_functionで開始する必要があります。 future インポートはPython 2.6以降でのみ動作するので、Python 2.5以前では2つの選択肢があります。もっと複雑なprintをもっと単純なものに変換することも、Python 2とPython 3の両方で動作する別のprint関数を使うこともできます。

>>> 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(標準出力)はすべてのUNIX/Linuxシステムに組み込まれているパイプです)はprintの代わりにはなりませんが、そうです場合によっては代替手段として使用できます。 Printは、入力を最後にスペースと改行で囲み、write関数を使用して書き込むラッパーです。これがsys.stderr.write()が速い理由です。

注: Loggingを使用してトレースやデバッグもできます。

#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

0
Vinay Kumar

試してください:

from sys import stderr


print >> sys.stderr, 'spam' 
0
Leon pvc