Как печатать на stderr в 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

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

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

Ответ 2

import sys
sys.stderr.write()

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

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

Ответ 3

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.

Ответ 4

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

Ответ 5

Никто еще не упоминал 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)

Ответ 6

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

print >> sys.stderr, 'spam' 

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

Ответ 7

Я использовал следующее: 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")

Ответ 8

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

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

Ответ 9

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

Ответ 10

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

Ответ 11

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

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

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

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

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

Ответ 12

Я работаю на python 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]$

Ну, кроме того, что небольшое введение, которое дает вам python, было прорвано в stderr (где еще он будет идти?), он работает.

Ответ 13

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

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

Ответ 14

Пытаться:

from sys import stderr


print >> sys.stderr, 'spam' 

Ответ 15

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

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

print: 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

Ответ 16

import logging
logging.basicConfig(format='[%(levelname)s] %(message)s')

logging.error('is error, alarm!')
logging.warning('is simple waring')

print('hello')

ведение журнала pydoc