Làm thế nào để in ra stderr trong Python?


1339

Có một số cách để viết vào 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)

Điều đó có vẻ mâu thuẫn với zen của Python # 13 , vì vậy có gì khác biệt ở đây và được có bất kỳ ưu điểm hay nhược điểm một cách này hay cách khác? Nên dùng cách nào?

Should Nên có một - và tốt nhất là chỉ có một - cách rõ ràng để làm điều đó.


46
Cách đầu tiên được liệt kê là một trong nhiều điều bị xóa trong Python 3. Sự đồng thuận dường như là cú pháp >> dù sao cũng xấu, và vì in bây giờ là một hàm, cú pháp sẽ không bao giờ hoạt động.
Steve Howard

24
Tôi sử dụng: sys.exit ('Lỗi: <lỗi văn bản>')
stark

1
Chỉ cần sử dụng in.
PythonMaster202

Câu trả lời:


1164

Tôi thấy đây là bản duy nhất ngắn + linh hoạt + di động + dễ đọc:

from __future__ import print_function
import sys

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

Hàm này eprintcó thể được sử dụng giống như printhàm chuẩn :

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

29
Chỉ cần một suy nghĩ: vì điều này sẽ nhập chức năng in, mọi "in" khác trong tập lệnh gốc bây giờ sẽ cần phải được "chức năng hóa" thêm "(" và ")". Vì vậy, đó là một cuộc đình công nhẹ chống lại phương pháp này, IMO.
Dân H

46
@DanH Có, điều này buộc bạn phải tạo mã Python3 sẵn sàng. Tôi đoán đây có thể là lý do tại sao nhiều người thực sự thích nó!
MarcH

18
@MarkH ... vâng, nó buộc bạn phải tạo mã Python3 sẵn sàng ... nó cũng buộc bạn phải làm NGAY BÂY GIỜ, chỉ cần in một số thông tin gỡ lỗi lên stderr ... mà tôi sẽ gặp nhiều rắc rối hơn trong hầu hết các tình huống khi tôi đang cố gắng gỡ lỗi một cái gì đó. (Tôi không muốn giới thiệu các lỗi cú pháp mới!) :-)
Dan H

30
FWIW mã này không bắt buộc bạn phải sử dụng phiên bản chức năng printtrong toàn bộ chương trình của bạn. Chỉ trong mô-đun chứa định nghĩa của eprint(). Đặt nó trong một tệp nhỏ, nhập eprinttừ tệp đó vào các tệp khác của bạn và bạn có thể tiếp tục sử dụng câu lệnh printmiễn là bạn muốn.
alexis

4
Ngoài ra, bạn chuyển đổi từ chức năng in sang chức năng in là một tìm kiếm đơn giản thay thế 2to3 đã tự động hóa cho bạn. Chỉ cần làm điều đó nếu bạn không có; python2 sẽ biến mất trong vòng chưa đầy 2 năm ... Một số điều trong khoảng từ 2 đến 3 có thể hơi rắc rối; chức năng in không phải là một trong số họ. Xem docs.python.org/2/library/2to3.html
bobpaul

548
import sys
sys.stderr.write()

Là lựa chọn của tôi, chỉ cần đọc nhiều hơn và nói chính xác những gì bạn định làm và di động qua các phiên bản.

Chỉnh sửa: trở thành 'pythonic' là suy nghĩ thứ ba đối với tôi về khả năng đọc và hiệu suất ... với hai điều này trong tâm trí, với python 80% mã của bạn sẽ là pythonic. danh sách hiểu là "điều lớn" không được sử dụng thường xuyên (khả năng đọc).


88
Đừng quên tuôn ra.
temoto

10
Ưu điểm của printcâu lệnh là dễ dàng in các giá trị không phải chuỗi, mà không phải chuyển đổi chúng trước. Nếu bạn cần một câu lệnh in, do đó tôi khuyên bạn nên sử dụng tùy chọn thứ 3 để sẵn sàng python 3
vdboor

56
sys.stderr.write()là không có gì giống như print. Nó không thêm một dòng mới.
Đại tá Panic

41
@temoto - stderr không được đệm, vì vậy không cần phải xả.
Matt

11
@SkipHuffman Ý bạn là os.linesep. Rốt cuộc, stderrchúng ta đang nói về. Đừng muốn giao diện điều khiển gây rối với dòng mới.
jpmc26

182

print >> sys.stderrđã biến mất trong Python3. http://docs.python.org/3.0/whatsnew/3.0.html nói:

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

Đối với nhiều người trong chúng ta, cảm thấy hơi bất thường khi xuống đích đến cuối lệnh. Thay thế

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

trông hướng đối tượng hơn, và thanh lịch đi từ chung chung đến cụ thể. Nhưng lưu ý rằng đó writekhông phải là sự thay thế 1: 1 cho print.


6
Tôi cho rằng đó là vấn đề ưu tiên, nhưng tôi không thấy điều gì xấu xí print('spam', file=sys.stderr). Nếu bạn làm đi làm lại nhiều lần, bạn có thể mã hóa chức năng 'eprint' như trong câu trả lời phổ biến nhất, nhưng trong trường hợp đó, tôi sẽ hỏi, có gì sai khi đăng nhập? stackoverflow.com/a/41304513/1450294
Michael Scheper

1
Một cách khác để làm rõ ý định sẽ được thực hiện with sys.stderr as dest:trước khi có một cuộc gọi thụt vàoprint("ERROR", file=dest)
MarkHu

131

Chưa có ai đề cập logging, nhưng đăng nhập được tạo riêng để truyền thông báo lỗi. Cấu hình cơ bản sẽ thiết lập một trình xử lý luồng ghi vào stderr.

Kịch bản này:

# foo.py
import logging

logging.basicConfig(format='%(message)s')
log = logging.getLogger(__name__)
log.warning('I print to stderr by default')
print('hello world')

có kết quả như sau khi chạy trên dòng lệnh:

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

bar.txt sẽ chứa 'hello world' được in trên thiết bị xuất chuẩn.


3
Theo kinh nghiệm của tôi, nhiều người sử dụng in để ghi thông điệp hơn là sử dụng ghi nhật ký. Tôi nghĩ python4 chỉ nên xóa bản in khỏi ngôn ngữ và buộc bạn phải sử dụng đăng nhập cho điều đó.
Mnebuerquo

1
Đây là câu trả lời tốt nhất !! ... Tôi đã vật lộn với bản in hoặc sys hoặc ai biết ... khi cần đăng nhập đúng cách ... cảm ơn vì ý tưởng hay
Carlos Saltos

129

Đối với Python 2, lựa chọn của tôi là: print >> sys.stderr, 'spam' Bởi vì bạn chỉ có thể in danh sách / dicts, v.v. mà không cần chuyển đổi nó thành chuỗi. print >> sys.stderr, {'spam': 'spam'} thay vì: sys.stderr.write(str({'spam': 'spam'}))


6
Cách Pythonic hơn để in một từ điển sẽ là với một cái gì đó giống như "{0}".format({'spam': 'spam'}), phải không? Tôi muốn nói rằng bạn nên tránh chuyển đổi rõ ràng thành chuỗi. Chỉnh sửa: Tôi vô tình mắc một ngữ pháp
luketparkinson

2
@lologneparkinson tất cả về gỡ lỗi - vì vậy, tôi nghĩ rằng, nên sử dụng mã đơn giản nhất có thể.
Frankovskyi Bogdan

88
Điều này không hoạt động trên Python 3, vì vậy bạn nên tránh nó trong mã mới.
JonnyJD

33

Tôi đã làm như sau bằng Python 3:

from sys import stderr

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

Vì vậy, bây giờ tôi có thể thêm các đối số từ khóa, ví dụ, để tránh trả lại vận chuyển:

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

2
Tôi sẽ đề nghị bạn cũng có thể sử dụng một phần, nhưng nhận ra rằng một phần gán stderr cho hàm tại thời điểm tạo của một phần. Điều này ngăn bạn chuyển hướng stderr sau đó vì một phần vẫn sẽ giữ đối tượng stderr ban đầu.
Hoàn trả

31

Tôi muốn nói rằng cách tiếp cận đầu tiên của bạn:

print >> sys.stderr, 'spam' 

là "Một cách rõ ràng để làm điều đó" Những người khác không thỏa mãn quy tắc số 1 ("Đẹp thì tốt hơn xấu.")


109
Ý kiến ​​khác nhau. Đây là điều ít rõ ràng nhất đối với tôi.
porgarmingduod

4
@AliVeli Không có dấu ngoặc đơn, đây là cú pháp Python <= 2 cũ hơn và do đó không tương thích với Python 3.
Hoàn trả

30
Tôi muốn nói rằng đây là phiên bản xấu nhất của cả 3
núi lửa

4
Điều đó >>có nghĩa là gì về mặt cú pháp? Tôi hiểu rằng đó là một nỗ lực để sao chép bash >, vì vậy đây có phải là một cú pháp đánh giày để làm việc đó không?
Dmytro Sirenko

2
@EarlGray Đó là một sự tiếp quản từ toán tử chèn luồng của C ++:std::cout << "spam";
Sean Allred

19

Điều này sẽ bắt chước chức năng in tiêu chuẩn nhưng đầu ra trên stderr

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

8
Tôi sẽ thêm một sys.stderr.flush ()
AMS

5
@AM - Tại sao? printkhông bao gồm một tuôn ra.
Cướp

4
Tại sao bắt chước khi bạn thực sự có thể làm điều đó?
Nhà vật lý điên

19

Trong Python 3, người ta chỉ có thể sử dụng print ():

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

gần như ra khỏi hộp:

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

hoặc là:

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

Điều này là đơn giản và không cần bao gồm bất cứ điều gì bên cạnh sys.stderr.


16

BIÊN TẬP Trong tầm nhìn xa, tôi nghĩ rằng sự nhầm lẫn tiềm ẩn với việc thay đổi sys.stderr và không thấy hành vi được cập nhật làm cho câu trả lời này không tốt bằng việc chỉ sử dụng một chức năng đơn giản như những người khác đã chỉ ra.

Sử dụng một phần chỉ giúp bạn tiết kiệm 1 dòng mã. Sự nhầm lẫn tiềm ẩn không đáng để lưu 1 dòng mã.

nguyên

Để làm cho nó dễ dàng hơn nữa, đây là một phiên bản sử dụng 'một phần', một trợ giúp lớn trong việc gói các chức năng.

from __future__ import print_function
import sys
from functools import partial

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

Sau đó bạn sử dụng nó như vậy

error('An error occured!')

Bạn có thể kiểm tra xem nó đang in ra stderr chứ không phải stdout bằng cách thực hiện các thao tác sau (mã quá mức từ 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!")

Nhược điểm này là một phần gán giá trị của sys.stderr cho hàm được bao bọc tại thời điểm tạo. Điều đó có nghĩa là, nếu bạn chuyển hướng stderr sau đó, nó sẽ không ảnh hưởng đến chức năng này. Nếu bạn có kế hoạch chuyển hướng stderr, thì hãy sử dụng phương pháp ** kwargs được đề cập bởi aaguirre trên trang này.


Mã của Corey Goldberg có chạy tốt nhất trên máy Rube Goldberg không? : P
Agi Hammerthief

2
BTW: "currying" là một từ khóa tìm kiếm hữu ích (hơn) nếu bạn muốn biết thêm về "một phần".
MarcH

5

Điều tương tự cũng áp dụng cho thiết bị xuất chuẩn:

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

Như đã nêu trong các câu trả lời khác, in cung cấp một giao diện đẹp thường thuận tiện hơn (ví dụ để in thông tin gỡ lỗi), trong khi viết nhanh hơn và cũng có thể thuận tiện hơn khi bạn phải định dạng đầu ra chính xác theo cách nhất định. Tôi cũng sẽ xem xét khả năng bảo trì:

  1. Sau này bạn có thể quyết định chuyển giữa stdout / stderr và một tệp thông thường.

  2. Cú pháp print () đã thay đổi trong Python 3, vì vậy nếu bạn cần hỗ trợ cả hai phiên bản, write () có thể tốt hơn.


4
Sử dụng from __future__ import print_functionlà cách tốt hơn để hỗ trợ cả Python 2.6+ và Python 3.
phoenix

4

Tôi đang làm việc trong python 3.4.3. Tôi đang cắt một ít gõ cho thấy cách tôi đến đây:

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

Nó có hoạt động không? Hãy thử chuyển hướng stderr đến một tệp và xem điều gì xảy ra:

[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]$

Chà, ngoài thực tế là phần giới thiệu nhỏ mà con trăn mang đến cho bạn đã bị nhét vào stderr (nó sẽ đi đâu khác?), Nó hoạt động.


2

Nếu bạn làm một bài kiểm tra đơn giản:

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))

Bạn sẽ thấy rằng sys.stderr.write () luôn nhanh hơn 1,81 lần!


Nếu tôi chạy này, tôi thấy một sự khác biệt nhỏ hơn nhiều. Thật thú vị khi hầu hết các câu trả lời đều bỏ qua cách in (python 3). Tôi chưa bao giờ sử dụng nó trước đây (quán tính), nhưng nghĩ rằng tôi sẽ chạy tập lệnh thời gian này và thêm chức năng in. Không thể so sánh trực tiếp câu lệnh in và chức năng in (nhập từ tương lai áp dụng cho toàn bộ tệp và che dấu câu lệnh in) nhưng viết lại mã này để sử dụng chức năng in thay vì câu lệnh tôi thấy tốc độ lớn hơn (~ 1.6 mặc dù có phần thay đổi ) ủng hộ chức năng in.
hamish

1
Kết quả của bài kiểm tra này là bằng cách nào đó sai lệch. In 'XXXXXXXXXXXXXXXXXXXX' thay vì 'X' và tỷ lệ giảm xuống còn 1,05 . Tôi giả sử hầu hết các chương trình python cần in nhiều hơn một ký tự.
Luôn hỏi

15
Tôi không quan tâm đến hiệu suất, vì một số thứ như in cảnh báo.
wim 31/12/13

Tôi biết đã được một lúc, nhưng bạn đã trả lời không kém sau bài viết của tôi ... Nếu bạn không quan tâm đến hiệu suất hơn tôi sẽ đề xuất cách thức pythonic hơn sẽ là sử dụng sys.stderr.write chứ không phải WTF?!? ">>" ký tự. Nếu không gian tên sys.stdout này quá dài, bạn có thể đổi tên nó ... (nghĩa là từ sys nhập stderr là stderr_fh). Sau đó, bạn có thể thực hiện stderr_fh.write ("blah")
ThePracticalOne

1
[3/3] Ngay cả khi điểm chuẩn này chính xác hơn, có lẽ không đáng lo ngại. Như Knuth đã viết: "Các lập trình viên lãng phí rất nhiều thời gian để suy nghĩ hoặc lo lắng về tốc độ của các phần không văn bản trong chương trình của họ và những nỗ lực này có hiệu quả thực sự có tác động tiêu cực mạnh khi gỡ lỗi và bảo trì. Chúng ta nên quên đi việc nhỏ tính hiệu quả, nói khoảng 97% thời gian: tối ưu hóa sớm là gốc rễ của mọi tội lỗi. "
Corey Goldberg

1

Nếu bạn muốn thoát khỏi một chương trình vì một lỗi nghiêm trọng, hãy sử dụng:

sys.exit("Your program caused a fatal error. ... description ...")

import systrong tiêu đề.


-2

Trả lời cho câu hỏi là: Có nhiều cách khác nhau để in stderr trong python nhưng điều đó phụ thuộc vào 1.) phiên bản python nào chúng ta đang sử dụng 2.) đầu ra chính xác mà chúng ta muốn.

Sự khác biệt giữa chức năng ghi của print và stderr: stderr : stderr (lỗi tiêu chuẩn) là đường ống được tích hợp trong mọi hệ thống UNIX / Linux, khi chương trình của bạn gặp sự cố và in ra thông tin gỡ lỗi (như truy nguyên trong Python), nó sẽ chuyển sang stderr ống.

print : print là một trình bao bọc định dạng các đầu vào (đầu vào là khoảng trắng giữa đối số và dòng mới ở cuối) và sau đó nó gọi hàm ghi của một đối tượng đã cho, đối tượng đã cho theo mặc định là sys.stdout, nhưng chúng ta có thể vượt qua một tập tin tức là chúng ta cũng có thể in đầu vào trong một tập tin.

Python2: Nếu chúng ta đang sử dụng python2 thì

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

Dấu phẩy của Python2 trong Python3 trở thành một tham số, vì vậy nếu chúng ta sử dụng dấu phẩy để tránh dòng mới sau khi in, thì trong Python3 trông giống như in ('Text to print', end = '') là lỗi cú pháp trong Python2 .

http://python3porting.com/noconv.html

Nếu chúng ta kiểm tra tương tự trên sceario trong python3:

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

Trong Python 2.6 có một lần nhập trong tương lai để in thành một hàm. Vì vậy, để tránh mọi lỗi cú pháp và các khác biệt khác, chúng ta nên bắt đầu bất kỳ tệp nào mà chúng ta sử dụng print () với nhập print_factor trong tương lai . Quá trình nhập trong tương lai chỉ hoạt động trong Python 2.6 trở lên, vì vậy đối với Python 2.5 trở về trước, bạn có hai tùy chọn. Bạn có thể chuyển đổi bản in phức tạp hơn thành một cái gì đó đơn giản hơn hoặc bạn có thể sử dụng một chức năng in riêng biệt hoạt động trong cả Python2 và Python3.

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

Trường hợp: Điểm cần lưu ý rằng sys.stderr.write () hoặc sys.stdout.write () (stdout (đầu ra tiêu chuẩn) là một đường ống được tích hợp trong mọi hệ thống UNIX / Linux) không phải là sự thay thế cho in ấn, nhưng có chúng ta có thể sử dụng nó như là một thay thế trong một số trường hợp. In là một trình bao bọc kết thúc đầu vào với không gian và dòng mới ở cuối và sử dụng chức năng ghi để ghi. Đây là lý do sys.stderr.write () nhanh hơn.

Lưu ý: chúng tôi cũng có thể theo dõi và gỡ lỗi bằng cách sử dụng Ghi nhật ký

#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/l Library / global.html # omgger-objects

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.