Как распечатать на stderr в Python?

1342

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

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

Wim
источник
46
Первый из перечисленных способов - это одна из многих вещей, удаленных в Python 3. Похоже, консенсус заключается в том, что синтаксис >> в любом случае был уродливым, и поскольку печать теперь является функцией, синтаксис никогда не будет работать.
Стив Ховард
24
Я использую: sys.exit ('Ошибка: <текст ошибки>')
абсолютное
1
просто используйте печать.
PythonMaster202

Ответы:

1167

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

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
Марш
источник
29
Только одна мысль: поскольку это будет импортировать функцию печати, все остальные «print» в оригинальном скрипте теперь нужно будет «функционализировать», добавив «(» и «)». Так что это небольшой удар по этому методу, ИМО.
Дан Х
46
@DanH Да, это заставляет вас делать ваш код готовым к Python3. Наверное, поэтому многим это действительно нравится!
МАРТ
18
@MarkH ... да, это заставляет вас делать ваш код готовым к Python3 ... это также заставляет вас делать это СЕЙЧАС, просто чтобы вывести некоторую отладочную информацию на stderr ... что я бы нашел больше хлопот в большинство ситуаций, когда я пытаюсь что-то отладить. (Я бы предпочел не вводить новые синтаксические ошибки!) :-)
Дэн Х
30
ПОЭТОМУ этот код не заставляет вас использовать функциональную версию printвсей вашей программы. Только в модуле, содержащем определение eprint(). Поместите его в небольшой файл, импортируйте eprintиз него в другие файлы, и вы можете продолжать использовать оператор printстолько, сколько захотите.
Alexis
4
Кроме того, вы конвертируете из функции печати в печать простую находку и замену, которую 2to3 уже автоматизирует для вас. Просто сделайте это уже, если у вас нет; Python2 исчезнет менее чем через 2 года ... Некоторые вещи между 2 и 3 могут стать немного сложнее; Функция печати не входит в их число. См. Docs.python.org/2/library/2to3.html
Бобпаул
548
import sys
sys.stderr.write()

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

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

Майк Рамирес
источник
88
Только не забудь промыть.
Темото
10
Преимущество printоператора заключается в удобной печати нестроковых значений без необходимости их предварительного преобразования. Если вам нужна инструкция для печати, я бы порекомендовал использовать третий вариант, чтобы быть готовым к Python 3
vdboor
56
sys.stderr.write()нет ничего подобного print. Это не добавляет новую строку.
Полковник Паник
41
@temoto - stderr не буферизуется, поэтому нет необходимости сбрасывать.
Мэтт
11
@SkipHuffman Вы имеете в виду os.linesep. Об этом stderrмы и говорим, в конце концов. Не хочу, чтобы консоль испортила неправильный перевод строки.
jpmc26
182

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.

Иоахим В
источник
6
Я полагаю, это вопрос предпочтений, но я не понимаю, в чем дело print('spam', file=sys.stderr). Если вы делаете это снова и снова, вы можете кодировать функцию «eprint», как в самом популярном ответе, но в таком случае, я бы спросил, что не так с журналированием? stackoverflow.com/a/41304513/1450294
Майкл Шепер,
1
Еще один способ прояснить намерение - сделать with sys.stderr as dest:до вызова с отступомprint("ERROR", file=dest)
MarkHu
131

Никто loggingеще не упоминал , но регистрация была создана специально для сообщения об ошибках. Базовая конфигурация настроит потоковый обработчик для записи в stderr.

Этот скрипт:

# foo.py
import logging

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

имеет следующий результат при запуске в командной строке:

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

и bar.txt будет содержать «привет мир», напечатанный на stdout.

сентиментальный
источник
3
По моему опыту, больше людей используют печать для регистрации сообщений, чем используют регистрацию. Я думаю, что python4 должен просто удалить печать с языка и заставить вас использовать протоколирование для этого.
Mnebuerquo
1
Это лучший ответ! ... я боролся с печатью или sys или кто знает ... когда нужна правильная регистрация ... спасибо за хорошую идею
Карлос
129

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

Франковский Богдан
источник
6
В "{0}".format({'spam': 'spam'})любом случае, более питонский способ печати словаря был бы с чем-то вроде этого , не так ли? Я бы сказал, что вам следует избегать явного преобразования в строку. Изменить: я случайно грамматику
luketparkinson
2
@luketparkinson - это все об отладке - так что, я думаю, предпочтительнее использовать как можно более простой код.
Франковский Богдан
88
Это не работает на Python 3, поэтому вам следует избегать этого в новом коде.
JonnyJD
33

Я сделал следующее, используя 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")
aaguirre
источник
2
Я собирался предположить, что вы также можете использовать частичное, но понял, что частичное присваивает stderr функции во время создания частичного. Это предотвращает перенаправление stderr позже, так как частичное все еще будет содержать исходный объект stderr.
Ребс
31

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

print >> sys.stderr, 'spam' 

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

Карл Ф.
источник
109
Мнения расходятся. Это наименее очевидно для меня.
porgarmingduod
4
@AliVeli Круглые скобки отсутствуют, это более старый синтаксис Python <= 2, поэтому он не совместим с Python 3.
Ребс
30
Я бы сказал, что это самая уродливая версия всего 3
вулкан
4
Что это >>значит синтаксически? Я понимаю, что это попытка скопировать bash >, так что это какой-то синтаксис для включения?
Дмитрий Сиренко
2
@EarlGray Это удержание от оператора вставки потока C ++:std::cout << "spam";
Шон Оллред
19

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

def print_err(*args):
    sys.stderr.write(' '.join(map(str,args)) + '\n')
Брайан В.
источник
8
Я хотел бы добавить sys.stderr.flush ()
AMS
5
@AMS - Почему? printне включает флеш
Робо
4
Зачем имитировать, когда вы действительно можете это сделать?
Безумный физик
19

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

Флориан Кастеллан
источник
16

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

РЭП
источник
Код Кори Голдберга лучше всего работает на машине Рубе Голдберга? : P
Agi Hammerthief
2
Кстати: «curry» - это (более) полезное ключевое слово для поиска, если вы хотите узнать больше о «частичном».
марта
5

То же самое относится к stdout:

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

Как указано в других ответах, print предлагает симпатичный интерфейс, который часто более удобен (например, для печати отладочной информации), в то время как запись выполняется быстрее и также может быть более удобной, когда вам необходимо точно отформатировать вывод. Я бы также подумал о ремонтопригодности:

  1. Позже вы можете переключиться между stdout / stderr и обычным файлом.

  2. Синтаксис print () изменился в Python 3, поэтому, если вам нужно поддерживать обе версии, лучше использовать write () .

Сеппо Энарви
источник
4
Использование from __future__ import print_function- лучший способ поддержки как Python 2.6+, так и Python 3.
phoenix
4

Я работаю в 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 (куда еще он пойдет?), Это работает.

user1928764
источник
2

Если вы делаете простой тест:

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 раза быстрее!

ThePracticalOne
источник
Если я запускаю это, я вижу гораздо меньшую разницу. Интересно, что большинство ответов игнорируют функцию print (python 3). Я никогда не использовал его раньше (инерция), но подумал, что запустил этот сценарий синхронизации и добавил бы функцию печати. Прямое сравнение оператора печати и функции невозможно (импорт из будущего применяется ко всему файлу и маскирует оператор печати), но при переписывании этого кода для использования функции печати вместо оператора я вижу большее ускорение (~ 1.6, хотя и несколько переменное) ) в пользу функции печати.
Хэмиш
1
Результат этого теста как-то вводит в заблуждение. Напечатайте «XXXXXXXXXXXXXXXXXXXX» вместо «X», и соотношение снизится до 1,05 . Я предполагаю, что большинство программ на python должны печатать больше, чем один символ.
Всегда спрашиваю
15
Меня не волнует производительность, например печать предупреждений.
Вим
Я знаю, что это было давно, но вы ответили так же долго после моего поста ... Если вы не гонитесь за производительностью, я бы посоветовал более питонским способом использовать sys.stderr.write, а не WTF?!? ">>" персонажи. Если это пространство имен sys.stdout слишком длинное, вы можете переименовать его ... (т.е. из sys import stderr как stderr_fh). Тогда вы можете сделать stderr_fh.write ("бла")
ThePracticalOne
1
[3/3] Даже если этот тест был более точным, о нем, вероятно, не стоит беспокоиться. Как писал Кнут: «Программисты тратят огромное количество времени на размышления или беспокойство по поводу скорости некритических частей своих программ, и эти попытки повышения эффективности на самом деле оказывают сильное негативное влияние при рассмотрении вопросов отладки и обслуживания. Мы должны забыть о небольших эффективность, скажем, в 97% случаев: преждевременная оптимизация - корень всего зла ».
Кори Голдберг
1

Если вы хотите выйти из программы из-за фатальной ошибки, используйте:

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

и import sysв шапке.

Феликс
источник
-2

Ответ на вопрос: есть разные способы печати stderr в python, но это зависит от того, 1.) какую версию Python мы используем 2.) какой именно вывод мы хотим получить.

Различие между print и функцией записи stderr : stderr : stderr (стандартная ошибка) - это канал, который встроен в каждую систему UNIX / Linux, когда ваша программа аварийно завершает работу и выводит отладочную информацию (например, трассировку в Python), она переходит к stderr труба.

Распечатать : print - это оболочка, которая форматирует входные данные (входные данные - это пробел между аргументом и символом новой строки в конце), а затем вызывает функцию записи для данного объекта, по умолчанию этот объект является sys.stdout, но мы можем передать файл, т. е. мы также можем напечатать вход в файл.

Python2: если мы используем python2, то

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

Завершающая запятая в Python2 в Python3 стала параметром, поэтому если мы используем запятые, чтобы избежать перехода на новую строку после печати, в Python3 это будет выглядеть как print ('Text to print', end = ''), что является синтаксической ошибкой в ​​Python2 ,

http://python3porting.com/noconv.html

Если мы проверим тот же сценарий выше в python3:

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

В Python 2.6 есть возможность импорта в функцию в будущем . Поэтому, чтобы избежать любых синтаксических ошибок и других различий, мы должны начинать любой файл, в котором мы используем print (), из будущего импорта print_function. Будущее импорта работает только в Python 2.6 и позже, поэтому для Python 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 (стандартный вывод) - это канал, встроенный в каждую систему UNIX / Linux), не заменяет печать, но да мы можем использовать его как альтернативу в некоторых случаях. Print - это оболочка, которая оборачивает ввод пробелом и символом новой строки в конце и использует функцию записи для записи. По этой причине 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

Винай Кумар
источник