Как распечатать на stderr в Python? - PullRequest
1158 голосов
/ 07 апреля 2011

Существует несколько способов записи в 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 , так в чем же разница и есть ли какие-либо преимущества или недостатки в том или ином случае? Какой способ следует использовать?

Должен быть один - и желательно только один - очевидный способ сделать это.

Ответы [ 15 ]

998 голосов
/ 20 февраля 2013

Я обнаружил, что это единственная короткая + гибкая + портативная + читаемая:

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
487 голосов
/ 07 апреля 2011
import sys
sys.stderr.write()

Это мой выбор, просто более читаемый и точно говорящий о том, что вы собираетесь делать, и переносимый между версиями.

Edit: «pythonic» - это третья мысль о читабельности и производительности ... с учетом этих двух вещей, с python 80% вашего кода будет pythonic. понимание списка - это «большая вещь», которая используется не так часто (удобочитаемость).

131 голосов
/ 08 ноября 2011

Для Python 2 мой выбор: print >> sys.stderr, 'spam' Потому что вы можете просто напечатать списки / диктанты и т. Д. Без преобразования в строку. print >> sys.stderr, {'spam': 'spam'} вместо: sys.stderr.write(str({'spam': 'spam'}))

120 голосов
/ 04 апреля 2013

print >> sys.stderr ушел в Python3. 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")

выглядит более объектно-ориентированным и элегантно переходит от общего к конкретному. Но обратите внимание, что write не является заменой 1: 1 для print.

89 голосов
/ 23 декабря 2016

Никто еще не упомянул 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 содержит «привет мир»)

(Примечание: logging.warn устарел устарел , используйте logging.warning вместо)

32 голосов
/ 07 апреля 2011

Я бы сказал, что ваш первый подход:

print >> sys.stderr, 'spam' 

- это "Один ... очевидный способ сделать это" Другие не удовлетворяют правилу № 1 ("Красиво лучше, чем безобразно. ")

30 голосов
/ 30 декабря 2013

Я сделал следующее, используя 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")
19 голосов
/ 06 октября 2012

Это будет имитировать стандартную функцию печати, но выводится на stderr

def print_err(*args):
    sys.stderr.write(' '.join(map(str,args)) + '\n')
17 голосов
/ 30 декабря 2013

РЕДАКТИРОВАТЬ В заднем плане, я думаю, что потенциальная путаница с изменением 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, а не в stdout, выполнив следующие действия (переопределение кода из 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, используйте метод ** kwargs, упомянутый aaguirre на этой странице.

8 голосов
/ 08 января 2019

В 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.

...