6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

コンテナの型ヒントのつけ方まとめ

Last updated at Posted at 2021-06-20

1. はじめに

2021年版Pythonの型ヒントの書き方」の「コレクションの種類の使い分け」を読んだ際「何をどう使い分ければいいんだ...」と絶句したので、簡単にまとめてみました。

2. 型ヒントの注意点

Python3.8までは、以下の書き方がされていました。

Python3.8以前
from typing import List, Sequence

def func(a: List[int], b: Sequence[float]) -> float:
    ...

Python3.9からは、typingからコンテナのgeneric versionを呼び出すのがdeprecatedになり、以下の書き方が推奨されています。

Python3.9以降
from collections.abc import Sequence

def func(a: list[int], b: Sequence[float]) -> float:
    ...

ちなみにPython3.7以降であれば、__future__.annotationsをimportすれば後者の書き方ができます。

Python3.7-3.8
from __future__ import annotations
from collections.abc import Sequence

def func(a: list[int], b: Sequence[float]) -> float:
    ...

この記事では、前者の書き方をもとに、型ヒントは全てtypingの形に合わせて記載します。

3. 対象のコンテナ

以下の8つのコンテナについて調べました。

  • tuple
  • list
  • deque
  • dict
  • Counter
  • defaultdict
  • set
  • frozenset

4. 継承関係の概観図

継承関係をまとめると、以下の図の通りになります。
(PlantUMLで作成しました。)
collections.png

以下については、図がごちゃごちゃになるため、今回は省きました。

  • MappingView
  • ItemsView
  • KeysView
  • ValuesView
  • OrderedDict

5. 型ヒントの使い分け目安

それぞれについて、mypy --strictがSuccessになる簡単な例を載せています。

5-1. Iterableforしたい

「forループしたいだけで型は何でもいい」という場合はこれが使えます。中でループしているsummaxもこれでいけます。

def func(values: Iterable[int]) -> int:
    return sum(values)

func((1, 2))
func([1, 2])
func(deque([1, 2]))
func({1: 'a', 2: 'b'})
func(Counter([1, 1, 2]))
func(defaultdict(str, {1: 'a', 2: 'b'}))
func({1, 2})
func(frozenset([1, 2]))

5-2. Sizedlen()したい

「サイズが欲しいだけで型は何でもいい」という場合はこれが使えます。

def func(values: Sized) -> int:
    return len(values)

func((1, 2))
func([1, 2])
func(deque([1, 2]))
func({1: 'a', 2: 'b'})
func(Counter([1, 1, 2]))
func(defaultdict(str, {1: 'a', 2: 'b'}))
func({1, 2})
func(frozenset([1, 2]))

5-3. Containerinしたい

「ある値が入っているか知りたいだけで型は何でもいい」という場合はこれが使えます。

def func(values: Container[int]) -> bool:
    return 1 in values

func((1, 2))
func([1, 2])
func(deque([1, 2]))
func({1: 'a', 2: 'b'})
func(Counter([1, 1, 2]))
func(defaultdict(str, {1: 'a', 2: 'b'}))
func({1, 2})
func(frozenset([1, 2]))

5-4. Collection:1から3まで全部したい

例えば下のように平均を求めてみると、IterableSizedだけではエラーが出てしまいます。ここでCollectionの出番です。

def func(values: Collection[int]) -> float:
    return sum(values) / len(values)

func((1, 2))
func([1, 2])
func(deque([1, 2]))
func({1: 'a', 2: 'b'})
func(Counter([1, 1, 2]))
func(defaultdict(str, {1: 'a', 2: 'b'}))
func({1, 2})
func(frozenset([1, 2]))

5-5. Sequenceobject[index]したい

添え字で中身を取得したい場合はこれが使えます。
ここからはコンテナが限定されて、対応するのはtuple, list, dequeです。

def func(values: Sequence[int]) -> Sequence[int]:
    return values[:2]

func((1, 2))
func([1, 2])
func(deque([1, 2]))

5-6. MutableSequence:5 + 代入や削除もしたい

Sequenceでは取得はできても、代入や削除しようとするとエラーになります。その場合はこれが使えます。
対応するのはlist, dequeです。

def func(values: MutableSequence[int]) -> MutableSequence[int]:
    values[0] = 3
    return values[:2]

func([1, 2])
func(deque([1, 2]))

5-7. Mapping:辞書だけど取り出すだけでいい

辞書っぽいコンテナから中身を取得したい場合はこれが使えます。
対応するのはdict, Counter, defaultdictです。

def func(mapping: Mapping[str, int]) -> int:
    return mapping['a']

func({'a': 1, 'b': 2})
func(Counter(['a', 'a', 'b']))
func(defaultdict(int, {'a': 1, 'b': 2}))

5-8. MutableMapping:7 + 代入や削除もしたい

Mappingでは取得はできても、代入や削除しようとするとエラーになります。その場合はこれが使えます。
対応するのはdict, Counter, defaultdictです。

def func(mapping: MutableMapping[str, int]) -> int:
    mapping['a'] = 3
    return mapping['a']

func({'a': 1, 'b': 2})
func(Counter(['a', 'a', 'b']))
func(defaultdict(int, {'a': 1, 'b': 2}))

5-9. AbstractSet:セットだけど何もしない

セットを、特に変更を加えずに使う場合はこれが使えます。
対応するのはset, frozensetです。

def func(values: AbstractSet[int]) -> AbstractSet[int]:
    return values & {1, 2}

func({1, 2})
func(frozenset([1, 2]))

5-10. MutableSet:9 + 代入や削除もしたい

AbstractSetでは追加や削除しようとするとエラーになります。その場合はこれが使えます。
対応するのはsetです。

def func(values: MutableSet[int]) -> MutableSet[int]:
    values.pop()
    return values

func({1, 2})

6. 参考

6
4
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
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?