Manjusaka

Manjusaka

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

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

私は Zhihu で答えを出さずにはいられませんでしたが、念のため、ブログで拡張して更新します。

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

始めに#

実際、この答えは非常に簡単です。歴史的な負担と ROI です。この現象がなぜ起こるのかを理解する前に、まず Type Hint が私たちにもたらすものを理解する必要があります。そして、Type Hint の前世今生を理解する必要があります。

現在の時点(2020.03)で見ると、Type Hint が私たちにもたらす目に見える利益は次のとおりです。

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

皆さんは Python 3.5 で PEP 484 が導入されて以来、Python Type Hint は成熟していると思っているかもしれません。しかし実際には、この時間は皆さんが想像しているよりもずっと短いのです。

さて、私たちは Type Hint の発展史における重要な節目を振り返る必要があります。

  1. PEP 3107 Function Annotations
  2. PEP 484 Type Hints
  3. PEP 526 Syntax for Variable Annotations
  4. PEP 563 Postponed Evaluation of Annotations

PEP 3107#

前述のように、皆さんが最初に Type Hint を認識したのは、14 年 9 月に提案され、15 年 5 月に通過した PEP 484 でしょう。しかし実際には、その雛形はずっと早くから存在しており、PEP 484 の文法は実際には 06 年に提案されたもので、3.0 に導入された PEP 3107 に基づいています。詳細は PEP 3107 -- Function Annotations を参照してください。

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

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

言い換えれば、関数のパラメータや戻り値に追加のメタ情報を追加するために、皆さんはさまざまな方法を駆使しており、PEP 318 のデコレーターを使用するものや、docstring を使うものがありました。コミュニティはこの現象を緩和するために、新しい構文糖を導入し、ユーザーがパラメータの署名や戻り値に追加情報を簡単に追加できるようにしました。

最終的に形成された文法は次のとおりです。

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

見覚えがありますか? そうです、3107 は実際にその後の Type Hint の基調を築きました。

  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 の type hint は基本的な公式規範を持ち、基本的な実用性を達成しました。この時点は 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 の拡張であり、この時点では hint の範囲は関数 / メソッドに限られています。そして上記のコードでは、3.5 の時期に私の left と right の変数に注釈を付けることができませんでした。プログラミング言語の基本要素の一つである変数が Type Hint で注釈を付けられないので、ある程度、こうした type hint の機能は閉じられていないと言えます。
  2. 循環参照、文字通りの意味で、コミュニティや StackOverflow で Type Hint における循環参照の問題を解決する方法は、一時的に人々を非常に頭を悩ませました。コミュニティ:何だこれは?

幸いにも、Python コミュニティはこの問題に気づき、二つの提案を通じてこの問題を解決しようとしました。

PEP 526#

問題 1 は PEP 526 -- Syntax for Variable Annotations の誕生を促しました。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 -- Data Classes の実現を推進しました。もちろん、これは後の話です。

さて、526 は上記の問題 1 を解決しましたが、問題 2 は解決していません。この問題は PEP 563 によって解決されます。

PEP 563#

循環参照の問題を解決するために、Python は PEP 563 -- Postponed Evaluation of Annotations を導入しました。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 以降、コミュニティは Type Hint を中心にエコシステムを構築し始めました。

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

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

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

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

この時点で、Python + Type Hint の真の力が発揮され始めました。これにより、皆さんが「なぜ Type Hint に切り替える必要があるのか?」という質問に答えることができるようになりました。私の推測では、IDE での快適さは重要な理由ではないでしょう。

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

こうして見ると、今までのところ、満打満算で一年半も経っていないことがわかります。ユーザーの習慣形成周期としては非常に短いです。ましてや、まだたくさんの Python 2 コードが残っています 23333

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

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

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

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

うん、だいたいこんな感じです。最近、仕事で心が疲れ果てている私も、少しは気を紛らわせるために、こんな駄文を書いて気持ちを落ち着けるしかありません。

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