ОБНОВИТЬ:
Прав ли я, полагая, что жесткое подключение оператора печати Python 2 означает, что это улучшение не может быть реализовано с помощью стандартного интерпретатора?
Нет, важные части оператора печати вообще не запрограммированы. print просто пишет в sys.stdout, который может быть любым объектом с методами write
и flush
. IPython уже полностью заменяет этот объект, чтобы в первую очередь получить стандартный вывод на блокнот (см. ниже).
Будут ли перспективы для Python 3 лучше, учитывая, что можно внедрить еще один слой в стек print() внутри ядра IPython? Особенно для тех, кто не перешел по ссылке Python, чтобы попасть сюда,
Нет, вам нужно переопределить sys.stdout, а не саму печать (см. выше, ниже и в других местах). Преимуществ у Python 3 здесь нет.
[никто не ожидает испанской инквизиции] В более общем смысле, можете ли вы указать на (не зависящие от языка) примеры доставки нескольких потоков на страницу?
Конечно, сам ноутбук IPython. Он использует идентификаторы сообщений и метаданные для определения источника сообщений stdout и, в свою очередь, того, где эти сообщения должны заканчиваться. Ниже, в моем первоначальном ответе на вопрос, который, по-видимому, никто не задавал, я показываю пример одновременного рисования вывода, поступающего из нескольких ячеек, чьи потоки выполняются одновременно.
Чтобы получить желаемое поведение обновления, вам, вероятно, потребуется сделать две вещи:
- замените sys.stdout своим собственным объектом, который использует протокол отображения IPython для отправки сообщений с вашими собственными метаданными, идентифицирующими поток (например,
threading.current_thread().ident
). Это должно быть сделано в диспетчере контекста (как показано ниже), поэтому оно влияет только на операторы печати, которые вы действительно хотите.
- напишите плагин IPython js для обработки вашего нового формата сообщений stdout, чтобы они не рисовались сразу, а сохранялись в массивах, ожидая рисования.
Оригинальный ответ (неправильный, но связанный вопрос):
Он основан на некоторых махинациях и частных API, но это вполне возможно с текущим IPython (возможно, это не навсегда).
Вот пример блокнота: http://nbviewer.ipython.org/4563193.
Чтобы сделать это, вам нужно понять, как IPython получает стандартный вывод на блокнот. Это делается путем замены sys.stdout объектом OutStream. Это буферизует данные, а затем отправляет их через zeromq при вызове sys.stdout.flush
, и в конечном итоге они оказываются в браузере.
Теперь, как отправить вывод в конкретную ячейку.
IPython протокол сообщений использует "родительский" заголовок, чтобы определить, какой запрос произвел какой запрос. Ответить. Каждый раз, когда вы просите IPython запустить некоторый код, он устанавливает родительский заголовок различных объектов (включая sys.stdout), чтобы их сообщения о побочных эффектах были связаны с сообщением, которое их вызвало. Когда вы запускаете код в потоке, это означает, что текущий parent_header — это просто самый последний execute_request, а не исходный, который запустил любой данный поток.
Имея это в виду, вот менеджер контекста, который временно устанавливает для родительского заголовка stdout определенное значение:
import sys
from contextlib import contextmanager
stdout_lock = threading.Lock()
@contextmanager
def set_stdout_parent(parent):
"""a context manager for setting a particular parent for sys.stdout
the parent determines the destination cell of output
"""
save_parent = sys.stdout.parent_header
# we need a lock, so that other threads don't snatch control
# while we have set a temporary parent
with stdout_lock:
sys.stdout.parent_header = parent
try:
yield
finally:
# the flush is important, because that's when the parent_header actually has its effect
sys.stdout.flush()
sys.stdout.parent_header = save_parent
А вот поток, который записывает родителя при запуске потока и применяет этот родитель каждый раз, когда выполняет оператор печати, поэтому он ведет себя так, как если бы он все еще находился в исходной ячейке:
import threading
class counterThread(threading.Thread):
def run(self):
# record the parent when the thread starts
thread_parent = sys.stdout.parent_header
for i in range(3):
time.sleep(2)
# then ensure that the parent is the same as when the thread started
# every time we print
with set_stdout_parent(thread_parent):
print i
И, наконец, записная книжка, связывающая все это вместе, с отметками времени, показывающими фактическую одновременную печать в несколько ячеек:
http://nbviewer.ipython.org/4563193/
person
minrk
schedule
18.01.2013