Pythonで型を指定する

Pythonは動的型付け言語なので、基本的に型を意識する必要がない。
が、VS CodeなどのIDEでインテリセンスがあまり効かないため、
どんなデータ型が渡されているかを推測しながら書く必要がある。

これは、静的型付け言語に慣れた身にはつらい。

#typingを利用
3.5から、typingモジュールが標準でセットされ、
型ヒントがサポートされた。
実行時エラーは発生しないものの、
VS Codeでコーディング時に次の挙動をしてくれる。

1. 型に応じたインテリセンスを提示
2. 定義した型が渡されなかった場合にエラー表示 

#基本的な使い方
関数定義時に利用したり、変数定義時に利用する

- 関数定義：
    - 返値のある場合：def func(args:*型*) -> *型* :
    - 返値のない場合：def funca(args:*型*) -> NoReturn:<br>※from typing import NoReturnをしておく</br>

型は、strやintなど色々指定できる

#型ヒントに自作クラスを指定する
どうやるんだろ？と思い、typingモジュールのドキュメントを探索。
typing.Type()という関数があったので、これを試してみることにする。

入門Python3の例題をちょっと改変
class_test.pyというクラスを作り、挙動を確認する

```python:class_test.py
import typing as tp

class Tail():
    def __init__(self, tail:str):
        self.__tail = tail
    @property
    def tail(self) -> str:
        return(self.__tail)
    @tail.setter
    def tail(self,tail:str):
        self.__tail = tail


class pBill():
    """型指定なし
    """
    def __init__(self, description):
        self.__description = description
    @property
    def description(self):
        return(self.__description)
    @description.setter
    def description(self,description):
        self.__description = description


class Bill():
    """型指定あり
    """
    def __init__(self, description:str):
        self.__description = description
    @property
    def description(self) -> str:
        return(self.__description)
    @description.setter
    def description(self,description:str):
        self.__description = description


class pDack():
    """型指定なし
    """
    def __init__(self, bill, tail):
        self.bill = bill
        self.tail = tail
    def about(self):
        print("This duck has a ",self.bill.description," and tail=",self.tail.tail)

class Dack():
    """型指定あり
    """
    def __init__(self, bill:tp.Type[Bill], tail:tp.Type[Tail]):
        self.bill = bill
        self.tail = tail
    def about(self):
        print("This duck has a ",self.bill.description," and tail=",self.tail.tail)


cbill = Bill('くちばし')
ctail = Tail('しっぽ')
cdack = Dack(cbill,ctail)
cdack.about()

### 以下のコードは実行時エラーなし　のはず
bill = Bill([]) 
tail = Tail({}) 
dack = Dack(bill,tail) 
dack2 = Dack(1,2) 
dack.about()

```

まずは挙動の確認から。
class_test.pyを実行してみる。
予想通り、エラーは起きない

```terminal:terminal
$ python class_test.py
This duck has a  くちばし  and tail= しっぽ
This duck has a  []  and tail= {}
```

続いて、インテリセンスの挙動を確認。
<b>型指定なしの場合</b>
self.bill にはどんな型が来るのか明示していないので、
self.bill. と打っても<b>何もでない。</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/4d5012d8-4886-d98b-c782-09fa45f529c3.png)

<b>型指定ありの場合</b>
self.bill に<b>Billクラスが渡されることを明示している</b>ので、
self.bill.と打つと<b>インテリセンスが表示される。</b>
また、descriptionはstr型とわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/4e982fa2-a8c6-5715-1101-11c0ec0e80de.png)

#補足
tp.Type[Bill]とか長ったらしくしなくても
通常の変数みたいに :クラス名 で大丈夫らしい。
こっちのほうがすっきりする。

```python:python
class Dack():
    """型指定あり
    """
    def __init__(self, bill:Bill, tail:Tail):
        self.bill = bill
        self.tail = tail
    def about(self):
        print("This duck has a ",self.bill.description," and tail=",self.tail.tail)
```



#参考
[typing --- 型ヒントのサポート¶](https://docs.python.org/ja/3/library/typing.html)
[Pythonではじまる、型のある世界](https://qiita.com/icoxfog417/items/c17eb042f4735b7924a3)