FlowingDev

サンドボックス内のPython: ブラウザで本物のCPythonを動かす

WebAssembly (WASM) が、本物のCPythonインタプリタやNumPyのようなライブラリを、サーバー不要でウェブブラウザ上で直接実行可能にする仕組みを学びましょう。

ツールを試す: Python Playground

一言で言うと

Pythonプレイグラウンドは、WebAssemblyという魔法のおかげで、サーバーもローカルへのインストールも一切不要で、人気のライブラリもろとも本物のPythonコードをウェブブラウザで直接書いて実行できる場所です。

それが解決する問題

ウェブの歴史のほとんどにおいて、ブラウザはJavaScriptの王国でした。ウェブページ上でコードを動かしたければ、JSで書く。それだけでした。もしあなたがPythonista(Python使い)で、例えばデータ分析スクリプトを実行してその結果をオンラインで表示したいと思ったら、ひと手間もふた手間もかかる作業をこなす必要がありました。Pythonコードを書き、それをサーバーで実行し、ウェブサイトに結果をフェッチさせる、という具合です。このクライアントサーバーモデルは強力ですが、簡単なスクリプトを試したり、コードスニペットを共有したりするためだけには、オーバーヘッドが大きすぎます。

この常識を打ち破ろうとした初期の試みは、賢いものでしたが不完全でした。BrythonやSkulptといったプロジェクトは、本質的にPythonからJavaScriptへのトランスレータでした。これらを使うと、Python風の構文で書いたコードがJavaScriptに変換され、ブラウザで実行されました。これは教育目的にはクールでしたが、本物のPythonではありませんでした。いわば、Pythonのコスチュームを着たJSプログラムだったのです。決定的に、このアプローチには2つの大きな欠点がありました。

  1. 常に公式のPythonインタプリタ(CPythonとして知られています)と全く同じように動作するわけではありませんでした。微妙な違いがあなたを躓かせる可能性がありました。
  2. データサイエンス界の巨人であるNumPyやPandasのように、パフォーマンスのためにC拡張に依存している広大なPythonライブラリのエコシステムを実行できませんでした。

根本的な問題は、python.orgからダウンロードする正真正銘の、公式のCPythonインタプリタを、どうやって厳格で安全なウェブブラウザのサンドボックス内で動かすか、ということでした。これを解決すれば、瞬時のプロトタイピング、セットアップ不要の教育ツール、そして共同作業やバグ報告のための真に共有可能で実行可能なコード例といった、可能性の世界が開かれます。それは、Pythonが遠いサーバー上に住む言語ではなく、ついにブラウザ内で第一級市民になれることを意味するのです。

内部の仕組み

C言語で書かれたプログラムであるCPythonを、JavaScriptを話すウェブブラウザ内で実行させるというのは、まるでデジタルな錬金術のように聞こえます。そして、ある意味その通りなんです!このプロセスにおける賢者の石は、WebAssemblyと呼ばれるテクノロジーです。

ヒーローはWebAssembly (Wasm)

WebAssembly、略してWasmが、この秘伝のタレです。これはあなたが書く言語ではなく、コンパイル先の言語だと考えてください。これは、現代のウェブブラウザがネイティブに近い速度で実行できる低レベルのバイナリ命令フォーマットです。C、C++、Rustのような高水準言語のためのポータブルなコンパイルターゲットとして設計されています。

つまり、ブラウザのJavaScriptエンジンがJavaScriptしか理解できないのではなく、今ではこの超最適化された低レベルのWasmバイトコードも理解できるようになったのです。これにより、Cで書かれた複雑なアプリケーションを、適切なツールを使って、ブラウザのタブ内で実行できる.wasmファイルにコンパイルできるのです。

CPythonをWasmにコンパイルする

これが「なるほど!」の瞬間です。標準で最も広く使われているPythonインタプリタは、Cで書かれているためCPythonと呼ばれています。CのコードはWebAssemblyにコンパイルできるので、CPythonインタプリタ全体をWebAssemblyにコンパイルできるということになります。

このプロセスは、Pyodideのようなプロジェクトが先駆者となり、PythonインタプリタのCソースコードを特別なコンパイラ(Emscriptenなど)に通します。出力は、OS用の典型的な.exeや実行ファイルではなく、cpython.wasmファイルになります。このファイルには、Pythonランタイム全体、つまりコードをパースし、メモリを管理し、命令を実行するための機構がすべて、ブラウザが実行できるフォーマットに詰め込まれています。

メモリ上のファイルシステム

ブラウザがこのcpython.wasmインタプリタをロードしたとき、それは文字通りインタプリタだけです。厳格なサンドボックス内で実行されており、あなたのコンピュータの実際のファイルシステムには一切アクセスできません(これはセキュリティ上の大きな利点です)。では、import numpyやimport mathはどのように機能するのでしょうか?これらのライブラリは、ファイルがどこかに存在する必要があります。

その解決策が、仮想ファイルシステムです。ブラウザのメモリの一部が、ハードドライブのように振る舞うために割り当てられます。プレイグラウンドがあなたのコードを実行する前に、Pythonの標準ライブラリと、あらかじめコンパイルされた人気パッケージ(NumPyなど)のWasmバージョンのバンドルを、このインメモリファイルシステムにプリロードします。Wasmで実行されているあなたのPythonコードがimport numpyを実行すると、インタプリタはこの仮想ファイルシステム内を探し、必要なファイルを見つけてロードします。ちょうどローカルマシンで行うのと同じように。

2つの世界を繋ぐ架け橋: JS <-> Python接続

さて、ブラウザのJSエンジン内でWasmとして動作するPythonインタプリタが手に入りました。どうやってコードを入力し、結果を出力するのでしょうか?これは、JavaScriptで書かれた「グルー(接着剤)」レイヤーによって処理されます。

ワークフローはこんな感じです:

  1. 初期化: ブラウザがページをロードします。JavaScriptコードがcpython.wasmインタプリタと仮想ファイルシステムパッケージをダウンロードします。
  2. 引き渡し: あなたがPythonコード、例えばprint("Hello from Python!")をテキストボックスに入力し、「実行」を押します。
  3. グルー: JavaScript関数があなたのコードを文字列として受け取り、Wasmモジュールによって公開されている特別な関数に渡します。
  4. Wasm実行: Wasm環境内で、CPythonインタプリタが起動します。あなたのコード文字列をパースし、実行し、出力を生成します(この場合は「Hello from Python!」を標準出力ストリームstdoutに書き込みます)。
  5. 出力のキャプチャ: JSグルーコードは、Wasmモジュールがstdoutやstderrに書き込むものをすべて傍受し、文字列としてキャプチャするように設計されています。
  6. 帰り道: JSコードはそのキャプチャした文字列を受け取り、ウェブページの出力エリアに表示します。より複雑なデータの場合、グルーレイヤーはPythonオブジェクト(辞書やリストなど)をJavaScriptの同等のもの(dict -> Object, list -> Array)に変換する翻訳を行います。

この架け橋により、JavaScriptによって管理されるブラウザのDOMと、Wasm内の隔離されたPythonランタイムという、2つの異なる世界がシームレスに通信できるようになります。

実話から学ぶ

データサイエンス面接での一幕

Sarahは、データサイエンス職の最終技術面接に臨んでいました。面接官は画面を共有しながら、「NumPyを使って、数値のリストに対する3点移動平均を計算するPython関数をさっと書いてもらえますか?」と言いました。Sarahは共有テキストエディタでまごまごしながら「ええと、こんな風にNumPyをインポートして…」と言う代わりに、操作権限を要求し、ブラウザでPythonプレイグラウンドを開き、コードを打ち込みました。彼女は関数を定義し、サンプル配列を作成して実行し、正しい出力を即座に示しました。そして、その動作するソリューションへのリンクをチャットで共有しました。面接官は、正しいコードだけでなく、その迅速で実践的なデモンストレーションに感銘を受けました。

教訓: ブラウザのプレイグラウンドは、ローカルセットアップの手間なくコンセプトを証明したりアルゴリズムをテストしたりするのに最適な、自己完結型の環境です。ライブコーディングやコラボレーションのための強力なツールになります。

本当に役立ったバグレポート

Alexは、あるオープンソースのデータ可視化ライブラリで、奇妙なエッジケースのバグを発見しました。入力データがNone値を含むタプルのリストである場合にのみ、チャートが不正にレンダリングされたのです。彼はGitHubにIssueを立てましたが、ただ問題を説明するだけでなく、Pythonプレイグラウンドを開きました。彼はエラーを再現するために必要な最小限のコード(インポート文、問題のあるデータ構造、バグを引き起こす関数呼び出し)を貼り付けました。それを実行してエラーメッセージを確認し、そのプレイグラウンドのリンクを「最小再現可能例 (Minimal Reproducible Example)」というタイトルでバグレポートに貼り付けました。ライブラリのメンテナーは、そのリンクをクリックするだけで、セットアップなしで即座にエラーを確認し、デバッグを開始することができました。

教訓: 共有可能で実行可能なコードスニペットは、バグ報告のゴールドスタンダードです。曖昧さをなくし、他の人が助けるための障壁を劇的に下げます。

「これ、どうやるんだっけ?」の瞬間

フロントエンド開発者のMayaは、複雑なReactコンポーネントの作業の真っ最中でした。特定のPython辞書構造を期待するバックエンドAPIにデータを渡す必要がありました。彼女は辞書内包表記の構文を正確に思い出せませんでした。ターミナルを開き、新しいファイルを作成して実行するという流れを断ち切る代わりに、彼女は新しいブラウザタブでPythonプレイグラウンドを開いただけでした。squares = {x: x*x for x in range(5)}とprint(squares)と打ち込み、実行ボタンを押すと、10秒もかからずに答えを得ました。彼女は構文を確認し、タブを閉じ、すぐにJavaScriptのコードに戻りました。

教訓: ブラウザのプレイグラウンドは、メインの開発ワークフローを妨げることなく、他の言語の構文や振る舞いを「コンテキストスイッチ」して確認する最速の方法です。

よくある間違いと落とし穴

  • ローカルファイルへのアクセスを期待する。 open('C:\\Users\\Me\\my_data.csv', 'r')のようなコードは書けません。プレイグラウンドは安全なブラウザのサンドボックス内で実行され、あなたのコンピュータのファイルには絶対にアクセスできません。データはコード内に直接貼り付ける必要があります。
  • 何でもpip installしようとする。 この環境には、あらかじめビルドされ、コンパイルされた人気パッケージのセットが付属しています。Python Package Index (PyPI) から任意のパッケージ、特にWasmにコンパイルされていない複雑なC依存関係を持つものはインストールできません。
  • 隔離されたセッションであることを忘れる。 あなたのコード、変数、インポートしたモジュールは、そのページの寿命の間だけ存在します。ブラウザのタブをリフレッシュすると、すべてが消去されます。これはステートレスな環境です。
  • ブロッキングコードや無限ループを実行する。 無邪気に見えるwhile True: passは、ブラウザのメインスレッドを乗っ取って、タブ全体をフリーズさせてしまいます。最終的にブラウザは諦めて、ページを強制終了するように促します。プレイグラウンドは、長時間実行される、計算量の多いタスクではなく、簡単なスクリプト用です。
  • 起動コストを無視する。 Wasmの実行は速いですが、数メガバイトのPythonインタプリタとファイルシステムをブラウザにロードするには少し時間がかかります。新しくロードされたページでの最初の実行は、その後の実行よりも常に遅くなります。

なぜ注目すべきか

ブラウザベースのPythonプレイグラウンドは、すべての開発者の仮想ツールベルトに入れておくべきものです。それは、コードを書きなぐるための、デジタル版の紙切れのようなものです。

こんな時に思い出してください:

  • .pyファイルを作成するという儀式なしに、小さなアルゴリズムやデータ変換をテストする必要があるとき。
  • Pythonの概念を教えたり説明したりしていて、誰かが実行して色々いじれる、ライブでインタラクティブな例を提供したいとき。
  • 同僚から来たPythonロジックの一部を理解したり、プロトタイプを作成したりする必要がある、非Python開発者のあなた。
  • Pythonのフル環境をインストールできない、ロックダウンされたマシン(Chromebookや会社のデバイスなど)を使っているとき。
  • ローカルのvenvやconda環境を管理する手間をかけずに、NumPyやPandasのようなライブラリを小さなタスクで試してみたいとき。

これは、本格的な計算や人気の開発者エコシステムを、ウェブブラウザというユビキタスなプラットフォームに直接持ち込むという、根本的なシフトを表しています。

もっと深く

  • WebAssembly.org — スペックやドキュメントを含む、Wasmに関するすべての公式情報源。
  • The Pyodide Project — Pythonとその科学技術スタックをWebAssemblyにコンパイルするための主要なプロジェクト。多くのブラウザ内Pythonツールの背後にあるエンジンです。
  • MDN WebAssembly Docs — Mozillaによる、ブラウザでWebAssemblyを使用するための優れた、開発者フレンドリーなドキュメント。
  • CPython source code — 真の勇者のために。これがPythonインタプリタ自体のCソースコードです。
  • Emscripten — C/C++コードをWebAssemblyにコンパイルするために使用されるツールチェーンであり、CPythonをブラウザに持ち込むための重要なコンポーネントです。

エディターはどうコードを理解するのか

色分けはプログラムの実行ではなく、言語パーサーによるものです。CodeMirror と Lezer がブラウザー内で記号と構文を解析します。候補にはキーワード、対応する場合のローカル名、スニペット、小さな組み込みリファレンスが含まれます。登録済みのシンボルにカーソルを重ねるとシグネチャが表示されます。候補が出ても、その API が実行環境に存在する保証はありません。対応するパーサーは構文エラーを検出しますが、型検査や実行の代わりにはなりません。Ruby と Lua はトークンベースのモードで、診断は限定的です。リモートの言語サーバーは使わず、コードは端末内に留まります。

CodeMirror & Lezer: MIT.

理論はOK。さあ手を動かそう — 100%ブラウザ内で。

ツールを試す: Python Playground