VSCodeのPythonで、型推定が強化された模様(2018/12/2現在)
2018/12/3 追記: Python language server extensionというものが必要そうです。 「Visual Studio Intellicode」のインストールが必要かもしれません。後ほど調べて追記します。
当ブログでは、Visual Studio Codeの紹介をよくやっています*1。
Pythonの紹介もその一つで、以下のような記事を書いています。
今回は、Visual Studio Codeの拡張機能Pythonがアップデートされ、カーソルを合わせた時のヒント表示が強化されたようです*2。
バージョン
| ツール | バージョン |
|---|---|
| Visual Studio Code | 1.29.1 |
| Python(本体) | 3.7.0 |
| Python(拡張機能) | 2018.11.0 (29 Nov 2018) |
使うソース
以前当ブログで使ったものです。これのchapter-16のものを例として使います。
当時の記事はこちら。
どう変わったか
以前がどうなっていたか、お見せするするものがないのですが…
例えば、dict型の変数を定義して、その変数にカーソルを合わせると、それはdictだと表示されます。
しかし、そのdictに対して、要素を追加すると、なんとその型を表示してくれるようになっています。
言葉だと分かりづらいので、例えば
# dict宣言 data = {} print(data)
だと、
dataは
dictである
という表示ですが、
# dict宣言 data = {} # 要素を追加 data["a"] = 1 print(data)
とすると、
dataはキーが
str、値がintのdictである
という表示に変わります。つまり、ソースの記述によって、変数の型を判断して表示してくれるようになりました。
具体例は以下の通りです。


以前、少なくとも2018/11/29までは、このような表示はなされていませんでした。
変わった(気がする)点を書いてみます。
戻り値の型表示
これも、以前はされていませんでした。
アノテーションで明示しなくても、型が明らかな場合は表示してくれます。
また、アノテーションがついている場合は、それを表示するようになりました。
- expression.py
from __future__ import annotations from abc import ABCMeta, abstractmethod from .exchanger import CurrencyExchanger class Expression(metaclass=ABCMeta): """式(演算)を表します。""" @abstractmethod def plus(self, addend: Expression) -> Expression: """加算""" pass @abstractmethod def reduce(self, bank: CurrencyExchanger, currency: str) -> Expression: """式を単純な形に変形する""" pass def times(self, multiplier: int) -> Expression: """指定倍""" pass
- Money.py(継承先。一部抜粋)
def plus(self, addend: Expression) -> Expression: """加算""" from .total import Total return Total(self, addend)
という状態だと、plusの戻り値はExpression(アノテーションの型)とTotal(定義で返している型)の二つが表示されます。
一方、アノテーションを消すと、戻り値はTotalのみとなります。


何が言いたいかというと、実際の定義に基づいた表示と定義に基づいた表示の二つを表示するようになっている、ということです。
上記画像を見てもらえばわかる通り、メソッドの引数についても同様です。
継承先や同じ型のメソッドも一緒に表示
継承(インターフェイスのような使い方)元のオブジェクトを受け取るメソッドを定義した場合、それが実装されているクラスの定義も表示されます。
- money.py
def reduce(self, bank: CurrencyExchanger, currency: str) -> Expression: rate = bank.rate(self.currency, currency) return Money(self.amount / rate, currency)
という定義で、bank.rateにカーソルを合わせると、本来ならCurrencyExchangerクラスのヘルプのみ表示されればよいですが、それを実装しているBankクラスのヘルプも表示されます。

ただし、出たり出なかったりします。動きがよくわかりません。(特にコメント)
listの中身がわかりやすくなった
これは、ちょうどよいサンプルが無いので、自作ソースで書きます。
たとえば、以下のようなクラスがあるとします。
class Point: def __init__(self, x: int, y: int): self._x = x self._y = y
そして、そのインスタンスをlistに格納します。
points = [] points.append(Point(0, 0)) points.append(Point(1, 0)) points.append(Point(3, 2))
すると、points変数は、list[Point]型である、とVSCodeが認識します。つまり、型指定Listと判断してくれます。

次に、このリストをforループしてみます。するとなんと、中身の型推論を行ってくれます!
私が記憶する限り、先日まではlistをループさせても型推論を行ってくれず、使いづらいなぁ…と愚痴をこぼしながら仕事をしていたので、この部分が強化されたのは間違いないと認識しています*3。
これのよいところは、内包表記が書きやすくなる、という点にも表れます。
ps = [p for p in points if p.x >= 1]
という書き方をすると、以前は
pがなんなのかわからんよ
と言っているのか、ヘルプなんて表示されませんでした。
型推論が働くことにより、
pはPointだよ
と分かるようになり、リスト内包表記をしている場合でもIntelliSenseの恩恵にあずかれるようになりました。
個人的には大変助かる機能です。パフォーマンスチューニングのためにリスト内包を書くのが、本当に楽になります…
おわりに
本日、偶然気づいた機能ですので、まだ調べ切っていない部分はあります。
しかし、11/29までは間違いなく無かった機能が追加されたようです。
Pythonは動的言語だというのは理解していますが、リスト内の型が明らかな場合ぐらいは判定してくれ、と思っていた(実際この一点でPythonのコーディングに嫌気がさしていたところ)ので、この改定は本当に助かります。
明日からはちょっとストレスが減りそうです。ほんとうに嬉しい。

