35
34

More than 3 years have passed since last update.

【Python】いろんな型について調べてみた!(typing)

Last updated at Posted at 2020-08-30

はじめに

python3.5 より python にも型ヒントという概念が組み込まれました。
使用するには、 組み込み型を使用するか import typing を使用し、型のチェックには mypy を使用します。

mypy について

インストール

まず、 mypy を使用するためにパッケージをインストールします。

$ pip install mypy

設定ファイル

mypy.ini を以下のように作成し、そこに設定情報を記入します。

mypy.ini
[mypy]
python_version = 3.8
disallow_untyped_calls = True
disallow_untyped_defs = True
disallow_untyped_decorators = True
disallow_incomplete_defs = True
check_untyped_defs = True
pretty = True

[mypy-django.*]
ignore_missing_imports = True

設定できるものについては、こちら を参照してください。

いろんな使用方法

組み込み型

組み込み型は、そのまま使用することができます。

num: int = 1
float_num: float = 1.11
is_something: bool = True
text: str = 'hoge'
byte_str: bytes = b'fuga'
arr: list = [0, 1, 2, 3]

Any 型

何の型が変数に入るか分からない場合は、 Any を使用します。
この型が指定されている場合は、型検査は行われません。

something: Any = Something()

全ての型の基底クラスである object も同じように使用できますが、object は、ある値が型安全な方法で任意の型として使えることを示すために使用し、Any はある値が動的に型付けられることを示すために使用します。

Dict 型

dictionary 型を使用する場合は、 typing.Dict を使用します。

dictionary: Dict[str, int] = {'hoge': 1, 'fuga': 2}

Tuple 型

タプル型を使いたい場合は、 typing.Tuple を使用します。

something: Tuple[str, int] = ('hoge', 1)

Set 型

set 型を使用したい場合は、typing.Set を使用します。
set 型は、重複しないようをのコレクションです。

something: Set[int] = {6, 7}

Sequence 型

シーケンス型を使用したい場合は、typing.Sequence を使用します。
シーケンス型は、順番(シーケンシャル)に処理するためのデータ構造です。

something: Sequence = [0, 1, 2]

Iterator 型

イテレータ型を使用したい場合は、typing.Iterator を使用します。
イテレータ型はイテラブルなクラスで __iter__() を持っている必要があります。

something: Iterator = IterableClass()

Mapping 型

マッピング型を使用したい場合は、typing.Mapping を使用します。
マッピング型は任意のキー探索を行うためのデータ構造で、Immutable な型です。

something: Mapping[str, int] = {'hoge': 1, 'fuga': 2}

Union 型

ユニオン型を使用したい場合は、typing.Union を使用します。
ユニオン型では、複数の型を指定することができます。

something_mapping: Mapping[str, int] = {'hoge': 1, 'fuga': 2}
something_union: Union[int, None] = something_mapping.get('hoge') # 1
something_union: Union[int, None] = something_mapping.get('piko') # None

Optional 型

typing.Optional は、typing.Union 型の None が必ず選択されているようなイメージです。

something_mapping: Mapping[str, int] = {'hoge': 1, 'fuga': 2}
something_optional: Optional[int] = something_mapping.get('hoge') # 1
something_optional: Optional[int] = something_mapping.get('piko') # None

Callable 型

関数を使用したい場合は、typing.Callable を使用します。

def something() -> bool:
    return True

something_callable: Callable = something

Literal 型

決まった値しか入らないことを保証したいときは、typing.Literal を使用します。

mode: Literal['r', 'rb', 'w', 'wb'] = 'r' # OK
mode: Literal['r', 'rb', 'w', 'wb'] = 'a' # NG

AnyStr 型

他の種類の文字列を混ぜることなく、任意の種類の文字列を許す関数によって使われるようにしたいときは、typing.AnyStr を使用します。

def concat(a: AnyStr, b: AnyStr) -> AnyStr:
    return a + b

concat(u"foo", u"bar")  # OK unicodeが出力されます
concat(b"foo", b"bar")  # OK bytesが出力されます
concat(u"foo", b"bar")  # NG unicodeとbytesが混ざっているためエラーになります

型のエイリアス

これまでの型を任意の型名で定義することができます。

Vector = List[float]
ConnectionOptions = Dict[str, str]
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]

NewType

異なる型を作るためには typing.NewType を使用します。

UserId = NewType('UserId', int)
some_id = UserId(524313)

ジェネリックス

Generic 型を使用するには、以下のようにします。

T = TypeVar('T')

# これが Generic 関数
# l にはどんな型でも良い Sequence 型が使える
def first(l: Sequence[T]) -> T:
    return l[0]

ユーザ定義のジェネリック型は以下のように使用できます。

T = TypeVar('T')

class LoggedVar(Generic[T]):
    def __init__(self, value: T, name: str, logger: Logger) -> None:
        self.name = name
        self.logger = logger
        self.value = value

    def set(self, new: T) -> None:
        self.log('Set ' + repr(self.value))
        self.value = new

    def get(self) -> T:
        self.log('Get ' + repr(self.value))
        return self.value

    def log(self, message: str) -> None:
        self.logger.info('%s: %s', self.name, message)

logger: LoggedVar[str] = LoggedVar('hoge', 'Test', Logger())
logger.get() # T は、str 型として扱われる

キャスト(typing.cast)

一度、定義した型を変更したいときは、typing.cast を使ってキャストします。
処理をできる限り速くするため、実行時には意図的に何も検査しません。

a = [4]
b = cast(List[int], a)
c = cast(List[str], a) # [4] が文字列になることはないので、変換したい場合は、自分で変換処理を追加する

定数(typing.Final)

定数を使用する場合は、typing.Final を使用します。

SOMETHING: Final[str] = 'Something'

おわりに

いかがだったでしょうか?
型を駆使することでより強固なアプリケーションの作成が行えるかと思います。
ただ、型を指定しているからといって、特別処理が早くなることはないので、そこはご注意ください。
実際に動作を見ていないものもあるので、間違っているところなど見つけましたら、お知らせいただけると助かります。

参考

35
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
34