Pythonの型を理解する

1. Pythonの型の基本
Pythonは動的型付けの言語であり、変数に値を代入する際に型を明示的に指定する必要はありません。代入された値に応じて、変数の型が自動的に決定されます。
x = 10 # int型
y = 3.14 # float型
name = "Alice" # str型
is_active = True # bool型
型を確認するには、type()
関数を使用します。
print(type(x)) # <class 'int'>
Python 3.5以降では、 型ヒント(type hints) を用いて関数や変数の型を明示することができます。
def greet(name: str) -> str:
return f"Hello, {name}"
2. Pythonの型の種類
数値型(Numeric Types)
-
int
:整数 -
float
:浮動小数点数 -
complex
:複素数x = 42
pi = 3.14159
z = 3 + 4j
文字列型(Text Type)
-
str
:文字列message = "Hello, World!"

シーケンス型(Sequence Types)
Pythonのシーケンス型は、順序を持つ要素のコレクションです。各要素にはインデックス(0から始まる)でアクセスできます。代表的なシーケンス型には次のようなものがあります。
list
(リスト)
可変長の順序付きのコレクションです。異なる型の要素を混在させることもできます。
fruits = ["apple", "banana", "cherry"]
fruits.append("orange")
print(fruits[1]) # banana
主な操作:
-
.append(x)
:末尾に追加 -
.remove(x)
:指定した要素を削除 -
.sort()
:要素を並べ替え(in-place)
tuple
(タプル)
リストと似ていますが、**不変(immutable)**である点が異なります。関数の戻り値として複数の値を返すときなどによく使われます。
point = (3, 4)
x, y = point
print(x + y) # 7
不変のため、変更や追加はできません。ハッシュ化可能なので辞書のキーにも使えます。
range
整数の連続したシーケンスを生成します。主に for
ループで使用されます。
for i in range(3):
print(i) # 0 1 2
list(range(2, 10, 2)) # [2, 4, 6, 8]
共通の特徴
すべてのシーケンス型は以下の操作をサポートしています(一部例外あり):
-
len(s)
:要素数を返す -
x in s
:要素の存在を確認 -
s[i]
:インデックスアクセス -
s[i:j]
:スライス
colors = ["red", "green", "blue"]
print(colors[0]) # red
print(colors[1:3]) # ['green', 'blue']
print("green" in colors) # True

マッピング型(Mapping Type)
Pythonのマッピング型は、キーと値(key-value)のペアを保持するデータ構造です。最も一般的なマッピング型は dict
(辞書)です。
dict
(辞書)
dict
は 可変で順序付き(Python 3.7以降) のデータ構造です。キーはハッシュ可能(__hash__()
を持ち、変更不可能)である必要があります。
※ ハッシュ可能: 一意に識別できて、変更されない(イミュータブル)
user = {
"name": "Alice",
"age": 30,
"is_active": True
}
print(user["name"]) # Alice
user["age"] = 31 # 値を更新
user["email"] = "a@example.com" # 新しいキーと値を追加
辞書の操作
-
アクセス:
d[key]
またはd.get(key)
-
追加/更新:
d[key] = value
-
削除:
del d[key]
またはd.pop(key)
-
キー・値・ペアの取得:
-
d.keys()
:すべてのキー -
d.values()
:すべての値 -
d.items()
:キーと値のペアのタプル
-
settings = {"theme": "dark", "volume": 50}
print(settings.get("theme")) # dark
print("volume" in settings) # True
print(settings.items()) # dict_items([("theme", "dark"), ("volume", 50)])
辞書内包表記(dictionary comprehension)
辞書内包表記とは、1行で辞書を生成する構文のことです。for
文と条件式を使って、柔軟かつ簡潔に辞書を作ることができます。
基本構文
{key_expr: value_expr for item in iterable}
たとえば、0〜4までの数値をキーとして、その2乗を値とする辞書を作成するには:
squares = {x: x * x for x in range(5)}
# 結果: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
条件付き内包表記(if文を使う)
特定の条件を満たす要素だけを辞書に含めたい場合は、if
を後ろに書きます。
# 偶数だけ
even_squares = {x: x * x for x in range(10) if x % 2 == 0}
# 結果: {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
enumerate()
と組み合わせる
リストのインデックスをキーに、値を辞書に変換できます。
fruits = ["apple", "banana", "cherry"]
fruit_dict = {i: fruit for i, fruit in enumerate(fruits)}
# 結果: {0: "apple", 1: "banana", 2: "cherry"}
zip()
と組み合わせる
2つのリストを組み合わせて辞書に変換することも可能です。
keys = ["name", "age", "city"]
values = ["Alice", 30, "Tokyo"]
user = {k: v for k, v in zip(keys, values)}
# 結果: {"name": "Alice", "age": 30, "city": "Tokyo"}
ネストした辞書(応用)
辞書内包表記の中にさらに内包表記を使えば、入れ子の辞書を作ることもできます。
nested = {x: {y: x * y for y in range(3)} for x in range(2)}
# 結果:
# {
# 0: {0: 0, 1: 0, 2: 0},
# 1: {0: 0, 1: 1, 2: 2}
# }
注意点
- 同じキーが複数回出現した場合、最後の値が有効になります。
- パフォーマンス的にも通常の
for
ループとほぼ同等です(読みやすさを優先)。

ネストされた辞書
辞書の値として他の辞書を持つことも可能です(ネスト)。
users = {
"alice": {"age": 30, "email": "a@example.com"},
"bob": {"age": 25, "email": "b@example.com"}
}
print(users["bob"]["email"]) # b@example.com
注意点
- 辞書のキーには
list
やdict
などの可変型は使用できません。 - 値にはどのような型でも使用できます。
集合型(Set Types)
Pythonの集合(set
/ frozenset
)は、重複のない要素の集まりを扱うためのデータ型です。数学的な集合と同じく、和・積・差・対称差などの集合演算が可能です。
set
(変更可能な集合)
- 中括弧
{}
またはset()
で作成します。 - 同じ要素が複数あっても自動的に重複が除かれます。
- 要素の順序は保持されません(順不同)。
fruits = {"apple", "banana", "apple", "orange"}
print(fruits) # {'apple', 'banana', 'orange'}
empty_set = set() # 空集合({}はdictになるので注意)
主な操作:
-
.add(x)
:要素xを追加 -
.remove(x)
:要素xを削除(存在しないとエラー) -
.discard(x)
:存在すれば削除、なくてもエラーにならない -
.clear()
:すべての要素を削除 -
.pop()
:任意の要素を1つ取り出して削除
numbers = {1, 2, 3}
numbers.add(4) # {1, 2, 3, 4}
numbers.discard(2) # {1, 3, 4}
numbers.remove(99) # KeyError になる(存在しない場合)
frozenset
(変更不可能な集合)
-
frozenset()
で作成するイミュータブルな集合。 - 集合自体の内容を変更できないが、辞書のキーなどに使える。
frozen = frozenset(["apple", "banana"])
print("banana" in frozen) # True
# frozenset は .add() や .remove() が使えない
集合演算
集合同士の演算も簡単にできます。
a = {1, 2, 3}
b = {2, 3, 4}
print(a | b) # 和集合: {1, 2, 3, 4}
print(a & b) # 積集合: {2, 3}
print(a - b) # 差集合: {1}
print(a ^ b) # 対称差集合: {1, 4}
メソッド形式でも使える:
a.union(b)
a.intersection(b)
a.difference(b)
a.symmetric_difference(b)
比較演算(部分集合など)
small = {1, 2}
big = {1, 2, 3, 4}
print(small.issubset(big)) # True
print(big.issuperset(small)) # True
print(small.isdisjoint({3, 4})) # True(共通要素なし)
応用例:重複の削除
data = ["apple", "banana", "apple", "orange"]
unique = list(set(data)) # ['orange', 'apple', 'banana'](順序は保証されない)
注意点
- 集合の要素にはハッシュ可能な(イミュータブルな)オブジェクトのみ使用可。
- 例:
int
,str
,tuple
(内容もイミュータブル)など -
list
,dict
,set
は使えない
- 例:
invalid = { [1, 2, 3] } # TypeError: unhashable type: 'list'

真偽値型(Boolean Type)
-
bool
:真 (True
) または偽 (False
)
is_valid = True
NoneType
-
None
:値が存在しないことを表す特殊な型
result = None
3. Pythonの型の応用例
型ヒントを使った関数定義
Pythonでは、関数の引数や戻り値に 型ヒント(type hints) を付けることで、コードの可読性・保守性・静的解析の精度を高めることができます。
基本構文
def 関数名(引数名: 型) -> 戻り値の型:
処理
例:
def greet(name: str) -> str:
return f"Hello, {name}"
この例では:
-
name
はstr
型であるべき - 戻り値は
str
型であることを表しています
複数の引数を持つ関数
def add(x: int, y: int) -> int:
return x + y
def area(width: float, height: float) -> float:
return width * height
戻り値がない関数
戻り値がない場合は -> None
を指定します。
def log_message(message: str) -> None:
print(f"[LOG] {message}")
オプショナル型(Optional)
引数が None
になる可能性がある場合は、Optional[...]
を使います。
from typing import Optional
def get_username(user_id: int) -> Optional[str]:
if user_id == 0:
return None
return "user" + str(user_id)
※ Optional[X]
は Union[X, None]
の別名です
複数の型を許容する(Union)
複数の型を受け取る可能性がある場合は Union
を使います。
from typing import Union
def stringify(value: Union[int, float]) -> str:
return str(value)
デフォルト引数にも型ヒント
def repeat(message: str, times: int = 1) -> str:
return message * times
コレクション型の型ヒント
from typing import List, Dict, Tuple
# 整数のリスト(例:`[1, 2, 3]`)を受け取る
def total(scores: List[int]) -> int:
return sum(scores)
# キーも値も文字列である辞書(例:`{"name": "Alice"}`)を返す
def get_user() -> Dict[str, str]:
return {"name": "Alice", "email": "a@example.com"}
# 整数が2つ入ったタプル(例:`(10, 20)`)を返す
def get_point() -> Tuple[int, int]:
return (10, 20)
可変長引数の型ヒント
-
*args
: タプルとして型指定 -
**kwargs
: 辞書として型指定
# 複数の整数を受け取る「位置引数」の可変長リスト
# 0個以上の `int` 型の引数を受け取る
def sum_all(*args: int) -> int:
return sum(args)
# 複数の名前付き引数(キーワード引数)を受け取り、すべての「値」が文字列
# 名前付き引数(キーと値のペア)を0個以上受け取る
def show_attrs(**kwargs: str) -> None:
for key, value in kwargs.items():
print(f"{key} = {value}")

Callable(関数を引数にする)
Pythonでは関数も「第一級オブジェクト」なので、他の関数の引数として関数を渡すことができます。
このような場合、型ヒントとして Callable
を使います。
基本構文
from typing import Callable
Callable[[引数の型1, 引数の型2, ...], 戻り値の型]
例:
def apply_twice(f: Callable[[int], int], x: int) -> int:
return f(f(x))
- apply_twice の引数
-
f
:int
を引数に取り、int
を返す関数 -
x
:int
型 - 戻り値:
int
型
-
使用例:
def double(n: int) -> int:
return n * 2
print(apply_twice(double, 3)) # 12(double(double(3)))
複数の引数を取る関数の型
def operate(a: int, b: int) -> int:
return a + b
f: Callable[[int, int], int] = operate
result = f(2, 3) # 5
戻り値がない関数
戻り値がない(None
を返す)関数の指定もできます。
def run_twice(action: Callable[[], None]) -> None:
action()
action()
def say_hello() -> None:
print("Hello!")
run_twice(say_hello)
任意の引数を許容する場合
引数の数や型がさまざまな関数を扱いたいときは、以下のように書きます。
from typing import Callable, Any
def call_it(f: Callable[..., Any]) -> None:
result = f()
print(result)
-
Callable[..., Any]
: 引数の数・型はなんでもよい、戻り値の型も何でもよい
注意点
-
Callable
の第一引数は「リストではなく中括弧(角カッコ)」で複数の引数型を指定します。 - Python 3.10 以降では
collections.abc.Callable
も使用可能ですが、typing.Callable
の方が型チェッカーとの相性が良いです。
型ヒントを強制するには?
Pythonは動的型付けなので実行時には型チェックされません。型チェックには mypy
や pyright
などのツールを使います。

None
を許容)
Optional型(Optional[X]
は、「型 X
の値 または None
が来る可能性がある」ということを示す型ヒントです。
これは次のように書いたものと同義です:
Optional[X] ≡ Union[X, None]
基本構文
from typing import Optional
def get_username(user_id: int) -> Optional[str]:
if user_id == 0:
return None
return f"user{user_id}"
-
user_id
が 0 の場合はNone
を返し、それ以外は文字列を返す関数 - 戻り値の型ヒントとして
Optional[str]
を使うことで、戻り値がstr
またはNone
であることが明示されます
使用例
name: Optional[str] = "Alice"
if name is not None:
print(name.upper())
else:
print("名前が未設定です")
どんなときに使う?
- 関数が正常時は値を返すが、失敗時や空のときは
None
を返す可能性があるとき - オブジェクトのプロパティが「設定されていない場合がある」とき
- デフォルト引数として
None
を使うとき
def greet(name: Optional[str] = None) -> str:
if name is None:
return "Hello, Guest!"
return f"Hello, {name}!"
Optional
は引数にも使える
def send_email(to: Optional[str]) -> None:
if to is None:
raise ValueError("送信先が必要です")
print(f"Sending email to {to}")
is None
でのチェックが基本
補足:Optional
な値を扱う場合は、is None
で明示的にチェックするのが基本です。Pythonには null安全演算子
のようなものはありません(ただし :=
や if val:
のような記法で簡略化は可能です)。

Union型(複数の型を許容)
Union[X, Y]
は、「X型またはY型のいずれかであればOK」という意味の型ヒントです。
1つの引数や戻り値が複数の型に対応する場面で使います。
基本構文
from typing import Union
def stringify(value: Union[int, float]) -> str:
return str(value)
-
value
はint
またはfloat
のどちらでもよい - 戻り値は
str
使用例
def length(x: Union[str, list]) -> int:
return len(x)
print(length("hello")) # 5
print(length([1, 2, 3])) # 3
Unionのネスト使用(Noneを含める)
def handle(data: Union[None, int, str]) -> str:
if data is None:
return "No data"
return str(data)
|
)
Python 3.10 以降の短縮構文( def stringify(value: int | float) -> str:
return str(value)
※ int | float
は Union[int, float]
と同じ意味
※ Python 3.10 以降のみ使用可能
注意点
-
Union型を使っても、関数内での型チェック(
isinstance
など)は必要になる場合がある-
Union[X, Y]
は「X型またはY型のどちらかである」という型ヒントです。 - しかし、関数の中では実際に どちらの型が渡ってきたのかはコードを実行してみないとわかりません。
- そのため、関数内で 具体的な型に応じた処理を行う場合には、
isinstance()
などを使って型を判定する必要があります。
-
-
Unionに渡す型は2つ以上でもOK
-
実行時には型が強制されるわけではない(型チェックは静的解析用)
よくある実用例
from typing import Union
def parse_price(price: Union[str, float]) -> float:
if isinstance(price, str):
return float(price.replace("¥", ""))
return price

ジェネリクス(例:List, Dict)
ジェネリクス(Generics)は、型の中の「要素の型」まで指定できる仕組みです。
たとえば、List[int]
と書くと、 「整数のみを要素に持つリスト」という意味になります。
from typing import List, Dict, Tuple
scores: List[int] = [80, 90, 100]
user: Dict[str, str] = {"name": "Alice", "email": "a@example.com"}
これにより、型チェッカーが各要素の型まで検査できるようになります。
よく使うコレクション型とジェネリクスの例
-
List[X]
:X型の要素を持つリスト -
Dict[K, V]
:キーがK型、値がV型の辞書 -
Tuple[X, Y]
:X型とY型の要素を持つ固定長タプル -
Set[X]
:X型の要素を持つ集合
✅ 具体例
from typing import List, Dict, Tuple
def total(scores: List[int]) -> int:
return sum(scores)
def get_user() -> Dict[str, str]:
return {
"name": "Alice",
"email": "a@example.com"
}
def get_point() -> Tuple[int, int]:
return (10, 20)
🧠 ジェネリクスを使う理由
- 要素の型まで明示されることで、IDEの補完が正確になる
- 静的型チェッカーがエラーを早期に検出できる
- ドキュメントとしてもわかりやすい
例:次の2つの型ヒントの違い
def f1(items: list) -> None:
...
def f2(items: List[str]) -> None:
...
-
f1
はどんな型のリストでも受け取れる(list
) -
f2
は「文字列のリストしか受け取れない」と明示されている(List[str]
)
🧪 ジェネリクスを使った関数の設計(応用)
独自の型引数を使って、型の再利用性を高めることもできます(TypeVar
を使う)。
from typing import TypeVar, List
T = TypeVar("T")
def first_item(items: List[T]) -> T:
return items[0]
-
T
は任意の型(int
,str
,User
, など) -
List[T]
を受け取って、T
を返す関数(同じ型で入出力される)
互換性と注意点
- Python 3.9 以降では
list[int]
,dict[str, int]
のように書けます(組み込み型が直接ジェネリックに対応)。 - それ以前のバージョンでは
from typing import List, Dict
を使う必要があります。
まとめ
- ジェネリクスは、コレクションの中身の型まで記述できる型ヒント
- よく使う:
List
,Dict
,Tuple
,Set
- 応用:
TypeVar
を使って汎用的な関数やクラスを定義できる

4. まとめ
Pythonの型ヒントは、静的型チェック・コード補完・ドキュメント性の向上を目的とした機能です。
特に、複雑な関数やデータ構造を扱う際に、エラーを未然に防ぐための強力なサポートになります。
✅ 基本型のヒント
関数や変数に明示的な型を付けることができます。
def greet(name: str) -> str:
return f"Hello, {name}"
-
name: str
→ 引数name
は文字列型 -
-> str
→ 戻り値は文字列型
✅ コレクション型のヒント(ジェネリクス)
リストや辞書など、要素の型まで指定できます。
from typing import List, Dict, Tuple
names: List[str] = ["Alice", "Bob"]
user: Dict[str, str] = {"name": "Alice", "email": "a@example.com"}
point: Tuple[int, int] = (10, 20)
-
List[X]
,Dict[K, V]
,Tuple[X, Y]
のように使う - Python 3.9 以降は
list[int]
,dict[str, int]
のように書ける
✅ Optional型(Noneを許容)
None
を返す・受け取る可能性がある値には Optional
を使う。
from typing import Optional
def get_name(user_id: int) -> Optional[str]:
if user_id == 0:
return None
return f"user{user_id}"
-
Optional[X]
はUnion[X, None]
と同じ意味
✅ Union型(複数の型を許容)
複数の型のどれかを受け取るときは Union
を使う。
from typing import Union
def to_str(value: Union[int, float]) -> str:
return str(value)
- Python 3.10 以降は
int | float
のような簡潔な書き方も可能 - 関数内では
isinstance()
で型の分岐が必要になることがある
✅ 可変長引数の型ヒント(*args, **kwargs)
def sum_all(*args: int) -> int:
return sum(args)
def show_attrs(**kwargs: str) -> None:
for key, value in kwargs.items():
print(f"{key} = {value}")
-
*args: T
→ T型の任意個の位置引数 -
**kwargs: T
→ T型の任意個のキーワード引数(キーは常にstr
)
✅ Callable(関数を引数にする)
関数を引数に受け取る場合には Callable
を使う。
from typing import Callable
def apply_twice(f: Callable[[int], int], x: int) -> int:
return f(f(x))
Callable[[引数の型...], 戻り値の型]
- 引数や戻り値の型が重要な意味を持つ関数に特に有効
✅ ジェネリクス(TypeVarの応用)
より汎用的な関数やクラスを定義したいときには、型変数 TypeVar
を使う。
from typing import TypeVar, List
T = TypeVar("T")
def first_item(items: List[T]) -> T:
return items[0]
- 入力の型と戻り値の型を連動させられる
- 再利用性の高いAPIを設計するのに便利
✅ バージョンによる記法の違い
Pythonバージョン | 記法 | 備考 |
---|---|---|
3.8以下 |
List[int] , Dict[str, T]
|
typing モジュールをimport |
3.9以降 |
list[int] , dict[str, T]
|
組み込み型でOK(PEP 585) |
📌 まとめのポイント
- Pythonの型ヒントは 静的解析のための仕組み(実行時には影響しない)
- 型ヒントを使うことで コードの可読性、保守性、バグの早期発見が可能になる
-
mypy
,pyright
,pylance
などと一緒に使うと効果が最大化される - バージョン差異や記法の違いに注意して、一貫したスタイルを心がけるとよい