Pythonを学び始めてしばらくすると、「== と is の違いって何?」「どっちを使えばいいの?」という疑問にぶつかる方が多いのではないでしょうか。
よくある混乱:
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True
print(a is b) # False ← なぜ?
一見似ているis
と==
ですが、実は使い道がまったく異なります。
理解しておくべき理由:
- バグの原因となりやすい
- Pythonらしいコードを書くために必須
- 他のプログラマーと協力する際の共通認識
- パフォーマンスにも影響する場合がある
この記事では、Pythonのis
演算子の意味・用途・注意点を、初心者向けにやさしく解説します。
第1章:Pythonのis演算子とは?基本概念を理解しよう

is演算子の基本的な意味
is
は、「同じオブジェクトかどうか」を判定する演算子です。
# 同じオブジェクトを参照している場合
a = [1, 2, 3]
b = a # bはaと同じオブジェクトを指す
print(a is b) # True(同じオブジェクトを指している)
print(id(a)) # 例:140234567890123
print(id(b)) # 例:140234567890123(同じID)
==演算子との根本的な違い
==
は、「中身が等しいかどうか」を判定します。
# 内容は同じだが、別々のオブジェクト
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True(中身は同じ)
print(a is b) # False(別のオブジェクト)
print(id(a)) # 例:140234567890123
print(id(b)) # 例:140234567890456(異なるID)
比喩で理解するisと==の違い
本の例で考えてみましょう:
# 同じ本を2人で見ている(is → True)
book1 = "Python入門"
book2 = book1 # 同じ本を指す
print(book1 is book2) # True
# 同じ内容の本を別々に持っている(== → True, is → False)
book1 = "Python入門"
book2 = "Python入門" # 内容は同じだが別の本
print(book1 == book2) # True(内容が同じ)
print(book1 is book2) # 実装によって異なる(文字列の場合)
id()関数でオブジェクトの正体を確認
# オブジェクトのユニークID(メモリアドレス)を確認
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(f"a のID: {id(a)}")
print(f"b のID: {id(b)}")
print(f"c のID: {id(c)}")
print(f"a is b: {a is b}") # False(異なるID)
print(f"a is c: {a is c}") # True(同じID)
第2章:is演算子の主な使いどころ
1. Noneとの比較(最も重要な用途)
PEP8(Pythonのコーディング規約)でも推奨されている使い方:
def process_data(data):
if data is None:
print("データがありません")
return
# データの処理
print(f"データを処理中: {data}")
# 使用例
process_data(None) # データがありません
process_data([1, 2]) # データを処理中: [1, 2]
なぜ== None
ではなくis None
を使うべきか:
class SpecialClass:
def __eq__(self, other):
# __eq__メソッドをオーバーライドして常にTrueを返す
return True
obj = SpecialClass()
print(obj == None) # True(誤判定!)
print(obj is None) # False(正しい判定)
2. ブール値(True/False)との比較
def check_status(status):
if status is True:
print("明確にTrueが設定されています")
elif status is False:
print("明確にFalseが設定されています")
else:
print("True/False以外の値です")
# 使用例
check_status(True) # 明確にTrueが設定されています
check_status(False) # 明確にFalseが設定されています
check_status(1) # True/False以外の値です
check_status(0) # True/False以外の値です
== True
とis True
の違い:
# これらは異なる結果になることがある
print(1 == True) # True(1は真値として扱われる)
print(1 is True) # False(1とTrueは別のオブジェクト)
print([] == False) # False(空リストは偽値だが、Falseと等価ではない)
print(bool([]) == False) # True
3. シングルトンオブジェクトとの比較
Pythonの特殊なオブジェクト:
# None, True, False は唯一のオブジェクト
print(None is None) # True
print(True is True) # True
print(False is False) # True
# Ellipsis(...)も唯一のオブジェクト
print(... is ...) # True
print(Ellipsis is ...) # True
4. 小さな整数・短い文字列の特殊ケース
Pythonでは、よく使われる値がキャッシュされます:
# 小さな整数(-5 から 256)はキャッシュされる
a = 100
b = 100
print(a is b) # True(同じオブジェクト)
# 大きな整数は別々のオブジェクトになることが多い
a = 1000
b = 1000
print(a is b) # False(実装によって異なる)
# 短い文字列もキャッシュされることがある
a = "hello"
b = "hello"
print(a is b) # True(多くの場合)
# 長い文字列や特殊文字を含む文字列
a = "hello world with spaces"
b = "hello world with spaces"
print(a is b) # False(実装によって異なる)
注意:これらの動作は実装依存です!
# 確実な動作を期待するなら==を使用
def safe_comparison():
a = 1000
b = 1000
# 数値の比較は == を使う
if a == b:
print("値が等しい")
# オブジェクトの同一性を確認したい場合のみ is を使用
if a is b:
print("同じオブジェクト")
else:
print("別のオブジェクト")
safe_comparison()
第3章:is演算子のよくある間違いと注意点

よくある間違いパターン
間違い①:数値や文字列の比較でis
を使ってしまう
問題のあるコード:
def calculate_score(points):
# 危険:数値の比較にisを使用
if points is 100: # 間違い
print("満点です!")
# 正しい書き方
if points == 100: # 正しい
print("満点です!")
# テスト
calculate_score(100) # 動作するかもしれないが、保証されない
calculate_score(50*2) # 期待通りに動作しない可能性
なぜ問題なのか:
# 同じ値でも異なるオブジェクトの場合がある
a = 300
b = 300
print(a == b) # True(値は同じ)
print(a is b) # False(別のオブジェクト)
# 計算結果の場合
c = 100 + 200
d = 150 + 150
print(c == d) # True
print(c is d) # False
間違い②:リストや辞書の内容比較にis
を使う
問題のあるコード:
def compare_data(expected, actual):
# 危険:リストの比較にisを使用
if actual is expected: # 間違い
print("データが一致しています")
else:
print("データが異なります")
# テスト
list1 = [1, 2, 3]
list2 = [1, 2, 3]
compare_data(list1, list2) # "データが異なります"(期待と違う)
正しい書き方:
def compare_data(expected, actual):
# 正しい:内容の比較には==を使用
if actual == expected: # 正しい
print("データが一致しています")
else:
print("データが異なります")
# 同一オブジェクトかどうかを知りたい場合は明確に区別
def check_same_object(obj1, obj2):
if obj1 is obj2:
print("同じオブジェクトです")
else:
print("別のオブジェクトです")
間違い③:is not
の使い方を間違える
間違った使い方:
# 文字列比較でis notを使用
name = "Alice"
if name is not "Bob": # 間違い
print("Bobではありません")
正しい使い方:
# Noneとの比較でis notを使用
data = get_user_data()
if data is not None: # 正しい
process_data(data)
# 文字列比較は!=を使用
name = "Alice"
if name != "Bob": # 正しい
print("Bobではありません")
パフォーマンスに関する注意点
import time
def performance_test():
# 大量のNoneチェックのパフォーマンス比較
data = [None if i % 2 == 0 else i for i in range(1000000)]
# is None の場合
start = time.time()
count1 = sum(1 for item in data if item is None)
time1 = time.time() - start
# == None の場合
start = time.time()
count2 = sum(1 for item in data if item == None)
time2 = time.time() - start
print(f"is None: {time1:.4f}秒, 結果: {count1}")
print(f"== None: {time2:.4f}秒, 結果: {count2}")
# performance_test() # is None の方が高速
第4章:isと==の違いを一目で理解する早見表

比較結果の違い
比較対象 | a == b | a is b | 解説 |
---|---|---|---|
[1,2] と [1,2] | True | False | 中身は同じでも別オブジェクト |
"hello" と "hello" | True | True またはFalse | 短い文字列はキャッシュされることも |
None と None | True | True | シングルトンオブジェクト |
a = b で作った変数同士 | True | True | 同じメモリアドレスを参照 |
100 と 100 | True | True | 小さな整数はキャッシュされる |
1000 と 1000 | True | False (多くの場合) | 大きな整数は別オブジェクト |
用途別の使い分け
目的 | 使用する演算子 | 例 |
---|---|---|
値の比較 | == | if score == 100: |
Noneチェック | is | if data is None: |
True/Falseの厳密チェック | is | if flag is True: |
オブジェクトの同一性確認 | is | if obj1 is obj2: |
リストや辞書の内容比較 | == | if list1 == list2: |
実践的なコード例
# 正しい使い方の例
def process_user_input(user_input):
# Noneチェック
if user_input is None:
return "入力がありません"
# 空文字チェック
if user_input == "":
return "空の入力です"
# 特定の値との比較
if user_input == "quit":
return "終了します"
return f"処理中: {user_input}"
# フラグ管理の例
def validate_settings(debug_mode, verbose_mode):
# 明確にTrueが設定されているかチェック
if debug_mode is True:
print("デバッグモードが有効です")
# Falseが明確に設定されているかチェック
if verbose_mode is False:
print("詳細出力が無効です")
# 真偽値的な判定(推奨される方法)
if debug_mode: # is True より簡潔
print("デバッグ機能を使用")
if not verbose_mode: # is False より簡潔
print("簡潔な出力")
第5章:実践的な応用例とベストプラクティス
関数の戻り値チェック
def get_user_data(user_id):
"""ユーザーデータを取得(見つからない場合はNoneを返す)"""
# データベースから検索(省略)
if user_id == "unknown":
return None
return {"id": user_id, "name": "User"}
def main():
user = get_user_data("123")
# 正しいNoneチェック
if user is not None:
print(f"ユーザー名: {user['name']}")
else:
print("ユーザーが見つかりません")
デフォルト値の処理
def create_config(debug=None, timeout=None):
"""設定を作成(Noneの場合はデフォルト値を使用)"""
# Noneの場合のみデフォルト値を設定
if debug is None:
debug = False
if timeout is None:
timeout = 30
return {
"debug": debug,
"timeout": timeout
}
# 使用例
config1 = create_config() # デフォルト値使用
config2 = create_config(debug=True) # debugのみ指定
config3 = create_config(debug=False, timeout=60) # 両方指定
クラスでの活用例
class DataProcessor:
def __init__(self):
self._cache = None
self._is_initialized = False
def initialize(self):
"""初期化処理"""
if self._cache is not None:
print("既に初期化済みです")
return
self._cache = {}
self._is_initialized = True
print("初期化完了")
def process(self, data):
"""データ処理"""
if self._cache is None:
raise RuntimeError("初期化されていません")
# 明確にFalseが設定されているかチェック
if self._is_initialized is False:
raise RuntimeError("初期化フラグがFalseです")
# 処理実行
result = f"処理済み: {data}"
self._cache[data] = result
return result
# 使用例
processor = DataProcessor()
processor.initialize()
print(processor.process("test data"))
エラーハンドリングでの活用
def safe_divide(a, b):
"""安全な除算(ゼロ除算の場合はNoneを返す)"""
if b == 0:
return None
return a / b
def calculate_average(numbers):
"""平均値を計算"""
if not numbers: # 空リストのチェック
return None
total = sum(numbers)
count = len(numbers)
result = safe_divide(total, count)
# Noneチェックでエラーハンドリング
if result is None:
print("計算エラーが発生しました")
return None
return result
# 使用例
print(calculate_average([1, 2, 3, 4, 5])) # 3.0
print(calculate_average([])) # None
まとめ
is
はPython独特の演算子で、「中身が等しいか」ではなく「同じオブジェクトか」を判定するために存在します。
本記事の重要ポイント
基本的な理解:
is
→ オブジェクトの同一性(identity)をチェック==
→ オブジェクトの等価性(equality)をチェックid()
関数 → オブジェクトのユニークIDを確認
適切な使い分け:
is None
およびis not None
→ Noneチェックに必須is True
/is False
→ 明確なブール値チェック- 数値・文字列・リスト・辞書の比較 → 常に
==
を使用
避けるべきパターン:
- 数値や文字列の値比較での
is
使用 - リストや辞書の内容比較での
is
使用 - キャッシュ動作に依存したコード
コメント