Manjusaka

Manjusaka

なぜ Python のタイプヒントは普及しなかったのか

Zhihu で面白い質問を見かけました、なぜ TypeScript はこれほど人気があるのに、型注釈付きの Python を書く人は少ないのか?

私は Zhihu で答えを出すのを我慢できなかったのですが、念のため、ブログで拡張して更新します。

ちなみに最近は本当に疲れ果てていて、記事を書くことでリラックスしたいと思っています。

始めに#

実際、この答えはとてもシンプルです。歴史的な負担と ROI です。この現象がなぜ起こるのかを理解する前に、まずはタイプヒントが私たちにもたらすものを理解し、その後にタイプヒントの前世今生を理解する必要があります。

現在の時点(2020.03)で見ると、タイプヒントが私たちにもたらす目に見える利益は以下の通りです。

  1. アノテーションを通じて、IDE のサポートと組み合わせることで、コード編集時の体験が向上します。
  2. mypy や pytype などのツールのサポートを通じて、CI/CD プロセスに静的型チェックを統合できます。
  3. pydantic や多くの新しいフレームワークのサポートを通じて、多くの重複作業を減らすことができます。

皆さんは Python 3.5 から PEP 484 が導入されたことで、Python タイプヒントはすでに成熟していると思っているかもしれません。しかし、実際にはこの時間は皆さんが想像するよりもずっと短いのです。

さて、私たちはタイプヒントの発展史における重要な節目を振り返る必要があります。

  1. PEP 3107 関数アノテーション
  2. PEP 484 タイプヒント
  3. PEP 526 変数アノテーションの構文
  4. PEP 563 アノテーションの評価の延期

PEP 3107#

前述のように、皆さんがタイプヒントを最初に認識したのは、14 年 9 月に提案され、15 年 5 月に通過した PEP 484 だと思います。しかし、実際にはその雛形はずっと早くから存在していました。PEP 484 の構文は、06 年に提案されたもので、3.0 に導入された PEP 3107 によって設計されたものです。詳細は PEP 3107 -- 関数アノテーション を参照してください。

PEP 3107 では、この提案の目的について次のように説明されています。

Python の 2.x 系列は、関数のパラメータや戻り値を注釈する標準的な方法が欠けているため、このギャップを埋めるためにさまざまなツールやライブラリが登場しました。一部は「PEP 318」で導入されたデコレーターを利用し、他は関数のドキュメンテーション文字列を解析して、そこに注釈を探します。
この PEP は、この情報を指定するための単一の標準的な方法を提供し、これまで存在していたメカニズムと構文の広範なバリエーションによって引き起こされる混乱を減らすことを目的としています。

要するに、関数のパラメータや戻り値に追加のメタ情報を追加できるようにするために、さまざまな方法が試みられました。PEP 318 のデコレーターを使用するものや、ドキュメンテーション文字列を使うものなどです。コミュニティはこの現象を緩和するために、新しい構文糖を導入し、ユーザーがパラメータの署名や戻り値に追加情報を簡単に追加できるようにしました。

最終的に形成された構文は次の通りです。

def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
    pass

見覚えがありますか?そうです、3107 は実際にその後のタイプヒントの基調を築きました。

  1. アノテーション可能
  2. 関数 / メソッド情報の一部として、インスペクト可能
  3. ランタイム

しかし、新たな疑問が生じます。この提案がなぜしばしば無視されるのか?それとも、具体的な時間点で見てみる必要があります。

この提案は最も早く 06 年に遡り、PEP3000 という、Python の歴史の中で最も有名な提案(つまり Python 3 の誕生を宣言するもの)で、Python 3 に導入されることが決定され、08 年に正式にリリースされました。

この時点で、3107 は二つの問題に直面しました。

  1. 06-08 年の間、コミュニティの主要なエネルギーは、Python 3 をなぜ導入するのか、またなぜ Python 3 に移行するのかという友好的な議論に集中していました。
  2. 3107 は実際には、皆に「あなたはアノテーションできる、アノテーション情報を簡単に取得できる」と伝えるだけでしたが、型の表現を抽象化する方法、例えば int 型のリストのようなものは、コミュニティの自主的な発展に依存していました。言い換えれば、放任です。

問題 1 は解決できず、時間がゆっくりと進むのを待つしかありませんでした。問題 2 は PEP 484 の誕生を促しました。

PEP 484#

PEP 484 という提案については、皆さんもある程度理解していると思いますので、具体的な内容についてはここでは説明しません。

PEP 484 の最大の意義は、PEP 3107 が築いた構文と基調を引き継ぎ、Python の型システムを合理的に抽象化したことです。これが重要な産物である typing です。この時点で、Python のタイプヒントは基本的な公式規範を持ち、基本的な実用性を達成しました。この時点は 15 年 9 月(9 月 13 日、Python 3.5.0 が正式にリリース)です。

しかし、実際には PEP 484 はこの時点でも基本的な使用を満たすに過ぎません。いくつかの批判的な例を挙げてみましょう。

まずは次のコードを見てみましょう。

from typing import Optional

class Node:
    left: Optional[Node]
    right: Optional[Node]

このコードは実際にはとてもシンプルです。標準的な二分木のノードの説明ですが、PEP 484 の中では、このコードは二つの問題を露呈します。

  1. 変数に対してアノテーションを行うことができません。前述のように、PEP 484 は本質的に PEP 3107 の拡張であり、この時点ではヒントの範囲は関数 / メソッドに限られています。上記のコードでは、3.5 の時期に私の left と right の変数にアノテーションを行うことができませんでした。プログラミング言語の基本要素の一つである変数がタイプヒントを持てないということは、ある程度、こうしたタイプヒントの機能が閉じられていないと言えます。
  2. 循環参照、文字通りの意味で、コミュニティや StackOverflow でタイプヒントの循環参照の問題を解決する方法は、一時的に人々を非常に頭を悩ませました。コミュニティ:何だこれは?

幸いなことに、Python コミュニティはこの問題に気づき、二つの提案を出して解決を図りました。

PEP 526#

問題 1 は PEP 526 -- 変数アノテーションの構文 の誕生を促しました。16 年 8 月に提案され、16 年 9 月に受け入れられました。16 年 9 月には BPO-27985 で実装されました。私の記憶では、これは Python コミュニティの中で数少ない議論が少なく、受け入れが早く、実装が早い PEP です。

526 では、Python は正式に変数にアノテーションを行うことを許可しました。class attribute でも普通の variable でもです。

class Node:
    left: str

これは可能です。

def abc():
    a:int = 1

これも可能です。

この提案に基づいて、Python 公式は PEP 557 -- データクラス の実現を推進しましたが、これは後の話です。

さて、526 は上記の問題 1 を解決しただけで、問題 2 は解決していません。この問題は PEP 563 によって解決されることになります。

PEP 563#

循環参照の問題を解決するために、Python は PEP 563 -- アノテーションの評価の延期 を導入しました。17 年 9 月にコミュニティが提案し、17 年 11 月に受け入れられ、18 年 1 月に GH-4390 で実装されました。

563 の後、上記のコードは次のように書けるようになりました。

from typing import Optional

class Node:
    left: Optional["Node"]
    right: Optional["Node"]

はい、484 の二つの問題がついに解決されました。

まとめ#

PEP 563 を重要な分岐点として、Python は最初に 18 年 1 月以降に初歩的に完全なエコシステムと生産可能性を持つようになりました。リリースバージョンを考慮すると、18 年 6 月、Python 3.7 が正式にリリースされた後のことです。

Python 3.6/7 以降、コミュニティはタイプヒントを中心にエコシステムを構築し始めました。

例えば、PEP 526 を利用してデータ形式を効率的に検証することができます。参照:pydantic

ちなみに、このライブラリは現在非常に人気のある新しいフレームワーク(私が現在最も好きなフレームワークでもあります)である FastAPI の基盤です。

大手企業も追随し始めました。例えば、Google の pytype や、Microsoft が提供する pyright が VSCode でのサポートを提供しています。

他にも多くの優れたライブラリ、例えば starlette などがあります。

この時点で、Python + タイプヒントの真の力が発揮され始めました。これにより、皆が「なぜタイプヒントに切り替えるべきなのか」という質問に答えることができるようになりました。IDE での快適さは、重要な理由ではないと私は思います。

技術的な決定を行う際には、その決定が私たちにもたらす利益が十分である必要があります。言い換えれば、十分な ROI が必要であり、単に「私たちがそれを好きだから」という理由ではありません。

こうして見ると、現在までの期間は、満たされたとしても一年半、二年を超えません。ユーザーの習慣形成周期としては非常に短いです。ましてや、まだ大量の Python 2 コードが残っているのです。

さて、比較として、TypeScript のリリース時期は 12 年 10 月に遡り、0.8 バージョンがリリースされた時点で、当時の TS は比較的完全な型システムを備えていたはずです。

TS は 8 年を要しましたが、Python はまだ長い道のりがあるかもしれません。

もちろん、この答えは技術的および歴史的な観点からこの問題について話したものに過ぎません。その他の多くの要因、コミュニティの駆け引きや妥協などについては、まだこの答えの範囲には含まれていません。興味がある方は、python-idea、python-dev、discuss-python などの場所で、これらの提案に関する歴史的な議論を探してみると非常に面白いです。

最後に、TS の成功にはもう一つの理由があります。それは、良い父親がいて、その父親が裕福であることです(逃

うん、だいたいこんな感じです。最近仕事が忙しくて心が疲れている私も、少しはリラックスするために、こうした雑文を書いて気持ちを落ち着けるしかありません。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。