これからのJupyterはVSCode以外に考えられない

皆さんJupyter使ってますか？使ってますよね？？

それでは何のJupyter使ってますか？普通のJupyterですか？JupyterLabですか？Google Colaboratoryですか？？

これからの時代は[**Jupyter Notebooks in VS Code**](https://code.visualstudio.com/docs/datascience/jupyter-notebooks)一択です。今からその理由をご説明します。きっと乗り換えたくなること間違いなし。

```python
class Dog:
    bark = "ワン！"
class Cat:
    meow = "ニャー！"

animal = Dog() if True else Cat()
animal.name = "ポチ"
setattr(animal, "type", "柴犬")
```

このコードの実行結果はどうなるでしょうか？

```python
animal.name # 'ポチ'
animal.type # '柴犬'
animal.bark # 'ワン！'
animal.meow # AttributeError: 'Dog' object has no attribute 'meow'
```

当然ですね。

着目したいのは、VSCodeがこの`animal`という変数をどのように認識しているかです。

# 動的解析と静的解析

ソースコードを解析し、適切な補完機能を提供するために取られるアプローチは、**動的解析**と**静的解析**に大別されます。

`dir`関数を思い出してください。

```python
dir(1) # ['__abs__', '__add__', '__and__', ...]
```

これは**動的解析**の結果です。IPythonによって取得できるので、例えばGoogle Colaboratoryでも補完結果が表示されます。

![動的解析](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534541/c70bd078-836c-7031-a3c3-f01497352774.png)

これに対し、**静的解析**では、ソースコード自体の意味を理解して解析します。例えば、下記のコードでは、`animal`は99%の確率で`Dog`ですが、1%の確率で`Cat`になります。

```python
animal = Dog() if random.random() > 0.99 else Cat()
```

VSCodeは、この文構造から`animal`を`Dog | Cat` (`Dog`または`Cat`である型)と認識します。

![Dog or Cat](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534541/b9855742-53a9-67e0-1fe5-1261d263e437.png)

このため、VSCodeは`bark`と`meow`をともに補完候補として表示させます。動的解析しか行うことのできない他のJupyter Notebook実装ではこの機能を実現することができず、`animal`が`Cat`である可能性を見落としてしまうかもしれません。

![強力な補完](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534541/9f5b4654-e4c2-29b4-4970-4a348b2691be.png)

VSCodeにこの能力を与えているのは、Microsoftの開発した[Pylance](https://github.com/microsoft/pylance-release)です。PylanceはTypeScript（！）で開発されたLanguage Serverで、軽量ながら非常に高度な解析を行うことができます。

動的解析と静的解析には、それぞれメリットとデメリットがあります。一方のメリットが他方のデメリットになる、といった感じですね。

* 動的解析
    * 存在するプロパティをすべて確実に表示できる
    * 実行してみないと解析できない
    * 前提条件によって存在し得るプロパティが異なる場合は当てにならない
* 静的解析
    * コードパスを網羅的に検討することができる
    * 実行しなくても解析できる
    * ソースコードから解析しづらい動的に生成されるプロパティを発見できない

# VSCodeのスゴいところ

VSCodeのJupyterが画期的なのは、**動的解析と静的解析のいいとこどり**ができるところです。もう一度最初のコードに戻ってみましょう。

```python
animal = Dog() if True else Cat()
animal.name = "ポチ"
setattr(animal, "type", "柴犬")
```

このコードを実行した後、`animal`のプロパティ候補として何が表示されるでしょうか？

![いいとこどり](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534541/1a943d92-9ca0-0d02-8bd6-68c84f308d45.png)

記号の異なる`bark`がリストに2回表示されていることにお気付きいただきましたでしょうか？実は、

| アイコン | 意味 |
|---|---|
| ![静的解析アイコン](https://raw.githubusercontent.com/microsoft/vscode-icons/master/icons/dark/symbol-variable.svg) | 静的解析で見つかったプロパティ |
| ![動的解析アイコン](https://raw.githubusercontent.com/microsoft/vscode-icons/master/icons/light/symbol-property.svg) | 動的解析で見つかったプロパティ |

のように意味が分かれています。`meow`は実際には存在しないけれどもコードパス上は存在し得るため静的解析のみで、`name`や`type`は静的解析では存在を発見しづらいので動的解析のみで、`bark`はどちらによっても発見し得るので2種類のアイコンが並んでいることになります。

# どのように活用するか

多くの場合、コードの静的解析の結果は、実行時のコンテキストに依存する動的解析の結果より信頼性の高いものです。しかしながら、pandas等、読み込んだデータによってプロパティが変わるようなライブラリを用いる場合、静的解析の結果のみでは発見できないプロパティが多く、開発速度が低下してしまうでしょう。

幸いなことに、今日ではPythonでも**type hinting**と呼ばれる、型情報を明示的に宣言する機能が使用できるようになりました。例えば、

```python
animal = Dog() if True else Cat()
```

といったコードでは、人間にとっては`animal`が`Dog`であることは明らかですが、現在のPylanceの静的解析能力ではこれを判定することができません（ちなみにTypeScriptは理解できます）。上記コードに型注釈をつけると、

```python
animal: Dog = Dog() if True else Cat()
```

のようになります。この場合、VSCodeでは`animal`が`Dog`であると正しく認識できるようになります。

![型注釈](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534541/58054a8e-9c77-03bd-a37f-703f95f97238.png)

データの前処理などで、pandas等データをぐちゃぐちゃに変化させるようなライブラリを使用する場合は動的解析に頼り、ある程度前処理が終わってデータ構造がはっきりとしたタイミングで静的解析が可能になるように型注釈をつける、といった運用にすれば、両者のメリットを最大限享受することができるようになるでしょう。それを可能にしてくれるのは、私が知る限りVSCodeのJupyterだけです。

# その他の機能

これ以外にも、VSCodeのJupyterは猛烈な進化を遂げていているようです。Microsoftはどこへ向かっているのか・・・。

## Live Share

ホストがLive Shareで共有することで、ゲストはホスト側で開かれているプロジェクトをGoogleドライブのように同時に編集することができるようになります。Google Colaboratoryでもできますがそれよりも圧倒的に低レイテンシで使い勝手が良いです。

ただ残念なことに記事執筆時点 (2021/07/10)ではゲスト側で補完は動作しません。通常のPythonファイルでは動作するので、アップデートに期待ですね。

![Live Share](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534541/b4a2a3d0-f40d-6ca2-63f0-e5ddd8f2a95f.png)

## Diff

お馴染みDiffの機能がついにJupyterでも使えるようになりました。右側パネルは普通に編集できますし、動的解析のみですが補完も効きます。すごい。

![Diff](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534541/a0be39c0-e054-8f54-2bbb-b440b0a4d8db.png)

## デバッガ

ついにJupyter Notebookのデバッガも使えるようになるそうなのですが（これまでは一度.pyに変換しないといけなかった）、まだExperimentalだそうで動作しません。早く試したい！