Как узнать, записала ли моя программа на Python что-то в sys.stdout или нет (в той же программе)? - PullRequest
0 голосов
/ 01 января 2019

Я делаю программу, которая имеет различные потоки управления в зависимости от того, было ли что-то записано в sys.stdout или нет.Сначала я сделал эту программу на своем Mac, и я мог сделать это

pos = sys.stdout.tell()
exec(some_code, globals)
if pos == sys.stdout.tell():
    # ...

Но оказалось, что я не мог использовать метод tell() в Linux, и это проблема для меня.Как я могу узнать, была ли затронута sys.stdout или нет в этом случае?

Одна мысль, которую я могу придумать, - это создать класс-оболочку для sys.stdout и sys.stdout.buffer, чтобы отслеживать все записи вызовов., хотя я не уверен, что это надежный способ сделать это.

Или я думаю, что могу попробовать contextlib.redirect_stdout.Но я не уверен, как я могу использовать это ..

РЕДАКТИРОВАТЬ: я работаю над этой утилитой https://github.com/bombs-kim/pythonp. Функция, которую я пытаюсь реализовать, заключается в автоматическом написании последнего выраженияsome_code в exec(some_code, globals) для стандартного вывода, когда не было вывода в стандартный вывод.

Ответы [ 2 ]

0 голосов
/ 01 января 2019

Я решил это самостоятельно, обернув оба sys.stdout.write, sys.stdout.buffer.write в python3.

import sys
write = sys.stdout.write

write_called = [False]


def make_write_hook(old_writer, flag: list):
    self = old_writer.__self__

    def new_writer(value):
        self.write = old_writer
        flag[0] = True
        old_writer(value)
    return new_writer


sys.stdout.write = make_write_hook(sys.stdout.write, write_called)
sys.stdout.buffer.write = make_write_hook(
    sys.stdout.buffer.write, write_called)

history = []
history.append(write_called[0])
print("hello world")
history.append(write_called[0])
print(history)

# ### output
# hello world
# [False, True]

Согласно моим наблюдениям над стандартным библиотечным кодом cpython, соглашение Python гласит, что все записи в стандартный вывод должныделается с помощью вызова sys.stdout.write или sys.stdout.buffer.write, а не прямого вызова типа os.fdopen(1, 'w').write.Это мое временное заключение, и я хотел бы, чтобы любой, кто знает Python лучше меня, подтвердил это.Спасибо всем!

0 голосов
/ 01 января 2019

Как я могу узнать, был ли затронут sys.stdout в этом случае?

Вы не можете , потому что stdout мог быть перенаправлен или конвейер (командой, используемой в вашей оболочке для запуска скрипта Python).Например, ваш пользователь мог перенаправить стандартный вывод на /dev/null (см. null (4) ), выполнив, например, ваш script.py как script.py > /dev/null, а затем ваш вопрос:даже не имеет никакого смысла.И ваш stdout может быть даже сокетом, fifo, устройством и т. Д. Кроме того, some_code может быть изменено *1022* (например, закрыть его, перенаправить с помощьюos.dup2, переопределите сам объект stdout Python и т. Д. ...)

Кроме того, ваша программа может даже не запускаться в терминале (например, crontab(5) задание или запуск вашей программы с at или ssh).См. Также t he tty demysified page.

stdout стандартный поток (обычно) устанавливается процессом вызова (обычно, но не всегда, некоторой оболочкой)который имеет fork (2) -ed и execve (2) -ed ваш скрипт.

И это не специфично для Linux, это Unixфилософия .Возможно, вы захотите прочитать какую-нибудь книгу по программированию для Unix или Linux (например, ALP ).

Вы можете обнаружить случай, когда ваш stdout является терминалом, используя ** isatty одна тысяча пятьдесят-четыре (3) * * +1055.Но это, безусловно, не охватывает все возможные варианты использования.

Linux имеет /proc/ (подробнее см. proc (5) ), и стандартный вывод также /dev/stdout aka /proc/self/fd/1 на котором вы можете сделать stat (2) (и, конечно, вы можете напрямую сделать fstat на STDOUT_FILENO, что равно 1).Но даже это не охватит все возможные варианты использования.

Задумывались ли вы о случае, когда ваша программа контролирует себя (например, pythonp pythonp ...)?

Я не являюсьОбязательно поймите ваши настоящие цели, но они прозвучат в моей голове о теореме Райса , и ваша проблема может быть неразрешимой.

...