Перенаправить стандартный вывод из Python для вызовов C - PullRequest
9 голосов
/ 10 января 2012

Это дополнительный вопрос из здесь , в частности относительно его ответа .


Из модуля python я вызываю исполняемый файл Hello World , который просто печатает Hello World на стандартный вывод. Я заинтересован в перенаправлении этого вывода на python StringIO и наткнулся на этот ответ, который почти подводит меня к решению.

Критическая часть этого ответа - этот сегмент кода:

1. def redirect_stdout():
2.     print "Redirecting stdout"
3.     sys.stdout.flush() # <--- important when redirecting to files
4.     newstdout = os.dup(1)
5.     devnull = os.open('/dev/null', os.O_WRONLY)
6.     os.dup2(devnull, 1)
7.     os.close(devnull)
8.     sys.stdout = os.fdopen(newstdout, 'w')

Также я хотел бы восстановить стандартный вывод, как это было до перенаправления.

Вопросы

  1. Что именно происходит в функции выше?
    • Что dup и dup2 делают?
    • Что такое /dev/null?
    • Что делает строка 8? (sys.stdout = os.fdopen(newstdout, 'w'))
  2. Как я могу сохранить стандартный вывод в StringIO объекте?
  3. Как я могу восстановить стандартный вывод после вызова моей Hello World программы?

Я почти уверен, что когда у меня будет ответ на мой вопрос 1, ответы на вопросы 2 и 3 будут простыми. Я решил опубликовать их в любом случае, чтобы, возможно, подтолкнуть ответ на вопрос 1 в направлении, куда я хочу идти.

Ответы [ 3 ]

11 голосов
/ 10 января 2012

Ниже я написал несколько дополнительных комментариев, которые должны прояснить, что происходит внутри функции redirect_stdout:

def redirect_stdout():
    print "Redirecting stdout"
    sys.stdout.flush() # <--- important when redirecting to files

    # Duplicate stdout (file descriptor 1)
    # to a different file descriptor number
    newstdout = os.dup(1)

    # /dev/null is used just to discard what is being printed
    devnull = os.open('/dev/null', os.O_WRONLY)

    # Duplicate the file descriptor for /dev/null
    # and overwrite the value for stdout (file descriptor 1)
    os.dup2(devnull, 1)

    # Close devnull after duplication (no longer needed)
    os.close(devnull)

    # Use the original stdout to still be able
    # to print to stdout within python
    sys.stdout = os.fdopen(newstdout, 'w')

Одна важная вещь, на которую следует обратить внимание, это то, что процесс получает три разных файловые дескрипторы из ОС при запуске:

  • стандартный ввод: 0
  • стандартный вывод: 1
  • стандартный вывод: 2

Как объяснено в комментариях, код выше использует преимущества файлового дескриптора для stdout и функций дублирования дескриптора файла, чтобы заставить код C использовать другой стандартный вывод, сохраняя при этом ссылку на исходный стандартный вывод в коде python, чтобыумеет печатать.

7 голосов
/ 10 января 2012

/dev/null - это специальный файл устройства (все в UNIX - это файл!), Который поглощает все записанное в него, как черная дыра. dup дублирует дескриптор файла. Если вы привыкли к Windows, дескриптор файла в UNIX - это специальное целое число, которое представляет открытый файл, это как дескриптор файла Windows.

Программа открывает /dev/null для записи (только), берет копию своего файлового дескриптора, закрывает открытый файл (потому что наличие файлового дескриптора достаточно для UNIX для записи в файл, вам не нужно оставьте ресурсы открытыми), затем присвойте открытый файл sys.stdout.

Помните, sys - это модуль Python, который представляет все виды системных ресурсов, таких как файловая система. Так, в UNIX sys.stdout будет представлять /dev/stdout, то есть системный STDOUT поток.

Итак, в целом этот код вводит Python в заблуждение, что /dev/null/ равен STDOUT, поэтому теперь каждый раз, когда ваша программа записывает в STDOUT, скажем, оператор print (функция в Python3), тогда действительно пишите /dev/null, и вы никогда не увидите полученный текст на своей консоли.

0 голосов
/ 10 января 2012

См. справочные страницы для функций времени выполнения C, которые лежат в основе этих функций Python.

По сути, они дублируют файловый дескриптор либо в новый файловый дескриптор (с dup()), либо в файловый дескриптор, указанный в вызове, с dup2().

...