Pythonの静的タイプの旅

6873 ワード

本文は掘金Python月の特別テーマの文章で、転載して出所を明記してください
江湖には「ダイナミックタイプは一時的に爽やかで、コードは火葬場を再構築する」という言葉が広く伝えられている.この言葉は一般的に静的言語擁護者の口から出ており、少し耳障りに聞こえるが、想像していたほど深刻ではない.Pythonは大型プロジェクトでの応用が多すぎて、Instagramが最高の例だ.
Pythonは動的言語として、変数を定義したり、関数の戻り値を定義したり、メソッドパラメータにデータ型を指定する必要がなく、ある程度コードを簡潔で柔軟にしたりして、プログラムの実行効率を捨てても、動的言語には不足があります.例えば:
1、IDEのスマートヒントは鶏の肋骨に比べて、変数のタイプを判断できないため、IDEは変数にそれらの属性と方法があることを知らないで、スマートヒントがないのは古い鳥にとってとても苦痛で、簡単な例を挙げて、strにstarttwithの方法があると印象して、しかし正しい書き方はstartswithで、sがあって、私はドキュメントを調べなければなりません.(ただし個人的には初心者はおとなしく実用エディタでコードを叩いて記憶を深めることをお勧めします)
2、コンパイル中、文法の間違いしか見つからず、タイプが一致しない問題はプログラムが本当に実行されてからしか分からない.セルテストで回避できますが、コード作成中にIDEが指摘してくれたらいいのではないでしょうか.
3、インタフェースの呼び出しはすべてドキュメントの注釈の説明に頼って、ある方法あるいは関数を呼び出して、戻り値とパラメータのタイプの説明はドキュメントによってしか確定できません.プログラマにdocstringやコメントを使用して関数のパラメータタイプや戻り値タイプを説明するように要求することができますが、最初はdocstringときちんと書かれていても、コードが更新された後、docstringが同期して更新されない可能性があります.
これらの問題は大規模なプロジェクト、特に多くの人が協力しているプロジェクトで特に際立っている.コード仕様、コードレビューが重要になります.これらの問題だけに,静的タイプの特性の導入を求めるコミュニティの声が高まっているため,Python 3.5,すなわちPEP 484にはタイプヒント(Type Hints)がある.関数を定義する場合は、関数の戻り値のタイプ、パラメータのタイプを指定できます.
以前、関数を書いたのは次のとおりです.
def greeting(name):
    return "Hello" + name

>>> greeting("bob")
'Hellobob'
>>> greeting(1)
TypeError: must be str, not int

ドキュメントやソースコードを見に行かないと、どのタイプの値を渡すことができるか分かりませんが、整数1を入力すると、プログラムが実行されるまでエラーが見つかりません.データ型チェックツールがプログラムが起動する前に事前にチェックすれば、プログラムエラーを避けることができます.
Python 3.5では、Type Hintという表記で、
def greeting(name: str) -> str:
    return 'Hello ' + name

上は静的タイプの書き方で、「:str」と「->str」が多くなり、前者はnameのタイプを説明し、後者は関数が値を返すタイプを指す.これにより,IDEのPyCharmのようなツールでもコードの問題を即座に発見できる.
もちろん、IDEのほかにもmypyというより強力な静的タイプチェックツールがあります.このツールもPythonの父GUidoが自ら刀を操作して実現した静的タイプチェックツールです.
pip install mypy

$ mypy test.py
test.py:4: error: Argument 1 to "greeting" has incompatible type "int"; expected "str"

タイプヒントがあれば、Pythonはコード呼び出し、再構築、さらには静的分析などの面でより良い効果があり、開発時に自分で型態検査を行う負担を軽減するだけでなく、型態上のヒントがあるため、過去のPython統合開発ツールではできなかった各種スマートヒント、再構築などの機能に統一的な参考基準がある.
ある意味では、タイププロンプトは補助機能にすぎません.データ型プロンプトを追加しましたが、Python解釈器では、タイププロンプト情報を直接無視し、インスタントタイプが間違っていてもプログラムの実行を阻止することはありません.
一方、変数のタイプについては、PEP 484において、タイプ注釈によって説明することができ、例えば、変数のタイプを注釈によって説明することができる.
from typing import List

x = []                # type: List[Employee]
y = [1, 2]            # type: List[int]
y.append("a")

上記のタイプのコメントは、xがEmployeeオブジェクトからなるリストでなければならないことを示しています.yはintからなるリストでなければなりません.整数リストyに文字列を追加した後、mypyでコードに問題があるかどうかを確認します.
mypy test.py
xx.py:3: error: Name 'Employee' is not defined
xx.py:5: error: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"

Python 3.6,すなわちPEP 526の提案では,変数注釈についてさらに最適化し,型の宣言を文法の一部とし,注釈よりも読解性が強く,例えば:
my_var: int  #           
my_var = 5  #       
other_var: int = 'a'  #             ,      ,               
print(other_var)
mypy xx.py  #        
xx.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int")

python test.py #      
a

タイプ・プロンプトはIDEインテリジェント・プロンプト、再構築に大きな便利さをもたらしますが、これらのタイプの情報の宣言によって、動的言語が肥大化しています.たとえば、次のようになります.
T = TypeVar('T')
S = TypeVar('S')
class Foo(Generic[T]):
    def method(self, x: T, y: S) -> S:
    # Body

これは汎用的な注釈で、Javaコードと変わらないように見えます.皮肉なことに、Javaにも動的言語の特性が加わり始め、例えばJava 10ではローカル変数タイプ推定特性があり、キーワードvarを使用して変数を定義することができ、データ型を指定する必要がなく、静的言語も動的言語特性の面で発展し始めたことを意味する.
public class VarTest {

    public static void main(String[] args) {
        var name = "java";
        System.out.println(name);
    }
}

では、静的言語が良いのか動的言語が良いのか、JavaとPythonはそれぞれ静的言語と動的言語の代表として、明らかな特徴はお互いの長所を参考にしていることであり、いわゆる天下の大勢は、分久必合、合久必分である.完璧な言語はありません.Pythonは柔軟ですが、制御性はそれほど強くありません.開放的な保護者のように、言語の処理において開発者に最大の自由を与えています.結局We are all consenting adults!逆にJavaを見ると、厳しい保護者のように、開発者一人一人に慎重に対応して、あなたが災いを起こすのを恐れています.