Примените textwrap.fill к каждой печати на скрипте python

Вы делаете

printf ("Hi %s,</br />", $name);

перед установкой файлов cookie, что запрещено. Вы не можете отправить какой-либо вывод перед заголовками, даже пустую строку.

0
задан jps 13 July 2018 в 07:47
поделиться

1 ответ

Monkeypatching print is выполнимо, но это не очень хорошая идея. Во-первых, что вы хотите, если кто-то делает print(spam, eggs)? Или print(spam, end='')? Или print(spam, file=outfile)?


Лучшее решение, вероятно, заменит sys.stdout на обертку.

Обычный sys.stdout - это простой старый текстовый файловый объект, TextIOWrapper , как и те, которые вы получаете из open, за исключением того, что когда вы пишете на него, он переходит на консоль вместо файла на диск.

И вы можете заменить его на что-либо еще, что соответствует протоколу TextIOBase .

И писать TextIOBase действительно просто. Все, что вам действительно нужно реализовать, это write и / или read и readline (в зависимости от того, будете ли вы выводить вывод, ввод или оба), и все, что нужно сделать нашей оболочке в write, - это буфер (f16) и передать их реальному файловому объекту внизу.

Как это:

import io
import sys
import textwrap

class Filler(io.TextIOBase):
    def __init__(self, file, width=70):
        self.file = file
        self.textwrapper = textwrap.TextWrapper(width=width)
        self.buf = ''
    def write(self, buf):
        self.buf += buf
        lines = self.buf.split('\n')
        self.buf = lines.pop()
        for line in lines:
            self.file.write(self.textwrapper.fill(line) + '\n')
    def close(self):
        if self.buf:
            self.file.write(self.textwrapper.fill(buf))
        self.buf = ''
        self.file.close()

sys.stdout = Filler(sys.stdout, 32)

print('Spam spam spam spammity ' * 10)
print('Spam', 'Eggs')
sys.stdout.textwrapper.width = 72
print('Spam ' + 'spam ' * 50, 'and eggs', sep='... ')
print('Spam', end=' ')
print('Eggs', end=' ')
print('Cheese')

Технически я думаю, что я могу обманывать здесь несколько способов:

  • Документы говорят, что ABC TextIOBase хочет detach, read и readline, даже если они здесь не имеют смысла. Но ABC, похоже, не применяет их как абстрактные методы, поэтому я не беспокоился.
  • I думаю, законно (и он работает) оставить encoding и errors установлен на None, так как мы просто переходим к другому TextIOBase и ожидаем, что он сделает кодировку, но я не могу найти ничего, что говорит , что это законно. И если какой-то код должен был проверить sys.stdout.encoding, чтобы увидеть, является ли это UTF-8 или что-то еще, это может быть проблемой.
  • Аналогично для newlines.

Кроме того, пересылка других методов в self.file может быть хорошей идеей, например fileno() и isatty(). Но я бы не стал беспокоиться о том, что любое приложение, которое хочет получить доступ к stdout как TTY, возможно, должно знать о Filler, которое мы застряли перед ним, а не просто прозрачно пройти через него.


g21] Это, конечно, все Python 3-specific. В Python 2:

  • sys.stdout является file, а не TextIOWrapper. API, который нужно обернуть, немного отличается и не так точно определен.
  • Если вы __future__ не используете функцию print в стиле 3.x, print является инструкцией, поэтому вы не можете обезвредить ее. (Я имею в виду, что вы могли бы написать крюк импорта, который байт-код взломал каждый байт-код PRINT_*, или, может быть, даже ввел .so, который заменяет PyObject_Print ... но кто все равно заботится? Это Python 2.)
1
ответ дан abarnert 17 August 2018 в 13:30
поделиться
  • 1
    Я был , чтобы опубликовать ответ, но он настолько похож на ваш, что я не буду беспокоиться. Однако вам следует подумать о создании экземпляра textwrap.TextWrapper и вызвать его метод .fill. Функция удобства textwrap.fill создает новый экземпляр для каждого вызова. – PM 2Ring 13 July 2018 в 08:53
  • 2
    @ PM2Ring Да, недостатком является то, что если вы хотите изменить ширину, вам нужно либо переслать @property в Filler, либо явно установить stdout.textwrapper.width, и теперь, когда я думаю об этом, это не так много недостаток. – abarnert 14 July 2018 в 02:31
  • 3
    В самом деле. :) И вверху, что ваш Filler __init__ может легко принять все Textwrap kwargs и передать их. Конечно, OP может не нуждаться в такой гибкости. Говоря об этом, было бы неплохо получить некоторые отзывы от OP ... – PM 2Ring 14 July 2018 в 05:22
Другие вопросы по тегам:

Похожие вопросы: