Jupyterのマジックコマンドで、指定したファイルを実行する「%run」。今回、あらためて調べてみるとちょっとした落とし穴になりうるところがあったので紹介します。
Contents
%run
そもそも「%run」とは、notebookからPythonスクリプトを実行できるマジックコマンド(ラインマジック)です。
その%runについて、公式のドキュメントを見てみると、以下のように記載されています。
This is similar to running at a system prompt
python file args
, but with the advantage of giving you IPython’s tracebacks, and of loading all variables into your interactive namespace for further use (unless -p is used, see below).
(拙訳:これはシステムプロンプトでのpythonコマンドによるファイル実行と似ていますが、IPython のトレースバックができ、さらに使用するためにすべての変数をインタラクティブな名前空間にロードするという利点があります)
つまり、セル上で宣言した変数等をスクリプトの実行時に持ち込むし、そのスクリプト中で定義した関数や変数をセルへと持ち帰るということを言っています。
ドキュメントでは「利点」として語られていますが、システムエンジニアから見ると、これが「不思議挙動」を起こしてしまう場合もあるように思えます。
たとえば、以下のコードセルがNotebookに定義されているとしましょう。
greeting = 'Good, morning.'%run greet.pyprint(greeting)
変数greetingが宣言・初期化され、そして同階層にあるgreet.pyを%runで実行してから、変数greetingの値を出力する、という簡単な処理です。ここで出力が期待されるのはgreetingの初期値、’Good, morning.’ です。
しかし、greet.pyが以下のように実装されていた場合、その期待に反する挙動を見せることになります。
greeting = 'Hello.'
なぜなら、先に述べた%runの仕様上、ここで ’Hello.’ が代入されたgreetingが実行元のコードセルまで持ち帰られるためです。

これに対し、pythonコマンドによる実行は変数を持ち越したりといったことがないので、期待通りの値が出力されます。

%runによる変数等持ち越しができるのはできるで良いとしても、例えばNotebookを長期に亘ってメンテナンスしていくような場合の可読性を考えると、実行ファイルはきちんとPythonモジュールとして切り出して、適切にimportしていく方が良さそうです。