アップデート:
Python 2 の print ステートメントがハードワイヤリングされているということは、この拡張機能を標準のインタープリターで実装できないことを意味していると私は信じていますか?
いいえ、print ステートメントの重要な部分はまったく組み込まれていません。write
print は単に sys.stdout に書き込みます。これはおよびflush
メソッドを持つ任意のオブジェクトにすることができます。IPython は、最初に stdout をノートブックに取得するために、このオブジェクトを既に完全に置き換えています (以下を参照)。
IPython カーネル内の print() スタックに別のレイヤーを忍び込ませることができることを考えると、Python 3 の見通しはさらに良くなりますか?特に Python リンクをたどってここにたどり着かなかった人にとっては、
いいえ - 必要なのは sys.stdout をオーバーライドすることだけであり、それ自体を印刷する必要はありません (上記、以下、および他の場所を参照)。ここには Python 3 の利点はありません。
[誰もスペインの異端審問を期待していない] もっと一般的に言えば、複数のストリームが 1 つのページに配信される (言語にとらわれない) 例を挙げていただけますか?
確かに - IPython ノートブック自体。メッセージ ID とメタデータを使用して、stdout メッセージの発信元と、これらのメッセージの最終的な送信先を決定します。以下に、明らかに誰も尋ねなかった質問に対する最初の回答で、スレッドが同時に実行されている複数のセルからの出力を同時に描画する例を示します。
必要な更新動作を得るには、おそらく次の 2 つのことを行う必要があります。
- sys.stdout を、IPython 表示プロトコルを使用して独自のスレッド識別メタデータを含むメッセージを送信する独自のオブジェクトに置き換えます (例:
threading.current_thread().ident
)。これは、コンテキスト マネージャー (以下のように) で行う必要があるため、実際に必要な print ステートメントにのみ影響します。
- 標準出力メッセージの新しい形式を処理するための IPython js プラグインを作成して、すぐに描画されるのではなく、描画されるのを待って配列に格納されるようにします。
元の回答(間違っていますが、関連する質問):
いくつかの悪ふざけとプライベート 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
そして、スレッドの開始時に親を記録し、print ステートメントを作成するたびにその親を適用する Thread は、元のセルにまだあるかのように動作します。
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/