Python – обнаруживает, когда мой объект записывается в stdout?

У меня довольно необычная просьба, я думаю … Я объясню, почему после того, как я объясню, что.

Какие

Я хочу, чтобы каждый раз, когда мой объект записывался в stdout, я мог выполнять побочные эффекты в это время. Так, например, когда я печатаю:

sys.stdout.write(instance_of_my_class) 

он должен выполнять побочные эффекты. Я сделал свой класс подклассом str и __call__ , __unicode__ , __str__ , __repr__ , index , __repr__ , encode , format , __format__ , __getattribute__ , __getitem__ и __len__ чтобы каждый из них __len__ заявление, указывающее, что они , но кажется, что sys.stdout.write вызывает ни одного из них для печати объекта.

Обратите внимание, что я специально говорю о sys.stdout.write а не, например, print – я обнаружил, что print вызывает __str__ на том, что он задан.

Зачем

Этот вопрос продолжается, когда ответ на цветную подсказку Python в Windows? прекращено.

Я обнаружил, что каждый раз, когда python должен отображать интерактивное приглашение, он вызывает __str__ на sys.ps1 и sys.ps2 , а затем сохраняет результаты, которые будут отображаться в командной строке. Это означает, что любые побочные эффекты в sys.ps2.__str__ вызываются сразу после sys.ps1.__str__ , но я хочу, чтобы они sys.ps1.__str__ , пока не sys.ps2 время отображать sys.ps2 .

Поэтому вместо того, чтобы возвращать str в sys.ps2.__str__ , я возвращаю свой подкласс str , который, я надеюсь, каким-то образом сможет поймать, когда на sys.stdout.write вызывается sys.stdout.write .

2 Solutions collect form web for “Python – обнаруживает, когда мой объект записывается в stdout?”

Почему не monkeypatch stdout.write?

 stdoutRegistry = set() class A(object): def __init__(self): self.stdoutRegistry.add(self) def stdoutNotify(self): pass original_stdoutWrite = sys.stdout.write def stdoutWrite(*a, **kw): if a in stdoutRegistry: a.stdoutNotify() original_stdoutWrite(*a, **kw) sys.stdout.write = stdoutWrite 

Интригующая проблема! Моя первая догадка заключается в том, что sys.stdout.write не вызывает метод __str__ потому что ваш объект уже является str (или, по крайней мере, его подклассом, который достаточно хорош для всех целей и задач) … поэтому никаких методов литья необходимы.

Дальнейшее исследование предполагает, что sys.stdout.write действительно никогда не хочет называть метод __str__

Подкласс

С небольшой интроспекцией вы можете узнать, какие методы вашего подкласса str вызывают sys.stdout.write (ответа не так много):

 class superstring(str): def __getattribute__(self, name): print "*** lookup attribute %s of %s" % (name, repr(self)) return str.__getattribute__(self, name) foo = superstring("UberL33tPrompt> ") sys.stdout.write(foo) 

Запуск в среде Unicode (Python 2.7, iPython notebook), это печатает:

 *** lookup attribute __class__ of 'UberL33tPrompt> ' *** lookup attribute decode of 'UberL33tPrompt> ' UberL33tPrompt> 

Это похоже на kludge-y, но вы можете переопределить метод decode подкласса для выполнения желаемых побочных эффектов.

Однако в среде, отличной от Юникода , нет поиска атрибутов .

Подборщик

Вместо того, чтобы использовать подкласс str , возможно, вам нужна какая-то «обертка» вокруг str . Вот уродливый исследовательский хак, который создает класс, который делегирует большинство своих атрибутов str , но который не является строго его подклассом:

 class definitely_not_a_string(object): def __init__(self, s): self.s = s def __str__(self): print "*** Someone wants to see my underlying string object!" return self.s def decode(self, encoding, whatever): print "*** Someone wants to decode me!" return self.s.decode(encoding, whatever) def __getattribute__(self, name): print "*** lookup attribute %s of %s" % (name, repr(self)) if name in ('s', '__init__', '__str__', 'decode', '__class__'): return object.__getattribute__(self, name) else: return str.__getattribute__(self, name) foo = definitely_not_a_string("UberL33tPrompt> ") sys.stdout.write(foo) 

В среде Unicode это дает в основном те же результаты:

 *** lookup attribute __class__ of <__main__.definitely_not_a_string object at 0x00000000072D79B0> *** lookup attribute decode of <__main__.definitely_not_a_string object at 0x00000000072D79B0> *** Someone wants to decode me! *** lookup attribute s of <__main__.definitely_not_a_string object at 0x00000000072D79B0> UberL33tPrompt> 

Однако, когда я запускаю среду, отличную от Unicode, definitely_not_a_string выдает сообщение об ошибке:

 TypeError: expected a character buffer object 

… это показывает, что метод .write подходит к интерфейсу буфера уровня C, когда ему не нужно выполнять декодирование Unicode.

Мое заключение

Кажется, что переопределение метода decode является возможной ошибкой в средах Unicode, поскольку sys.stdout.write вызывает этот метод, когда ему нужно декодировать str в Unicode.

Тем не менее, в средах, отличных от Unicode, кажется, что .write не выполняет каких-либо поисков атрибутов, а просто переходит к протоколу символьного буфера уровня C, поэтому нет способа перехватить его доступ из кода Python. Действительно, help(sys.stdout.write) проверяет, что это встроенная функция (она написана на C, а не на Python).

  • python - как я могу перенаправить вывод unittest? Очевидное решение не работает
  • Общайтесь с подпроцессом, не дожидаясь завершения подпроцесса в окнах
  • Как реализовать оболочку stdin, stdout?
  • Как я могу захватить вывод stdout дочернего процесса?
  • Доступ к распечатанному выходу вызова функции
  • Как я могу перенаправить вывод вывода функции в python
  • многопоточность с помощью wx.TextCtrl (или базового GTK +)
  • Захват вывода из буферизованной программы StdOut
  • python unicode обрабатывает различия между print и sys.stdout.write
  • удалить последнюю строку STDOUT в Python
  • Как я могу отправить многопроцессорную обработку процесса python на Tkinter gui
  •  
    Interesting Posts for Van-Lav

    Как написать setup.py для включения git-репо в качестве зависимости

    Получение ввода пароля командной строки в Python

    Запретить чтение данных из пустого FIFO из блокировки

    Как gzip при загрузке в s3 с помощью boto

    Как изменить мой float на два десятичных числа с запятой в качестве разделителя десятичной точки в python?

    Как объявить словарь со встроенной функцией

    Как фильтровать фрейм данных дат в определенный месяц / день?

    Получать подсчет нескольких отфильтрованных подзапросов в шаблоне

    Получение python MySQLdb для запуска на Ubuntu

    Настроить тему sphinxdoc

    Piton tkinter's entry.get () не работает, как я могу его исправить?

    Как добавить настраиваемый тип к разборным типам укропа

    pySerial очень странное поведение … Код работает, когда выполняется в оболочке, но не в скрипте

    render ('django.contrib.auth.views.login'), указывающий на другой URL, чем {% url 'django.contrib.auth.views.login'%}

    Развертывание Django на alwaysdata.com

    Python - лучший язык программирования в мире.