Python ==演算子とis演算子の違い完全ガイド – 使い分けとベストプラクティス
==演算子とis演算子とは?
Python の == 演算子と is 演算子は、どちらも比較に使用されますが、全く異なる概念を比較しています。この違いを正しく理解することで、バグの少ない効率的なPythonコードが書けるようになります。
基本的な違い
==演算子(等価性の比較)
- オブジェクトの値が等しいかを判定
__eq__()メソッドを呼び出す- 内容を比較する
is演算子(同一性の比較)
- オブジェクトのアイデンティティが同じかを判定
- メモリ上の同じオブジェクトかを確認
id()関数の結果を比較
基本的な比較例
1. 数値での比較
# 等価性の比較
a = 1000
b = 1000
print(a == b) # True(値が同じ)
print(a is b) # False(異なるオブジェクト)
# オブジェクトIDを確認
print(id(a)) # 140712345678912 (例)
print(id(b)) # 140712345678944 (例:異なるID)
2. 小さな整数での特殊なケース
# -5から256までの整数は同じオブジェクト
x = 100
y = 100
print(x == y) # True
print(x is y) # True(同じオブジェクト)
# 大きな数値は異なるオブジェクト
x = 1000
y = 1000
print(x == y) # True
print(x is y) # False(異なるオブジェクト)
3. 文字列での比較
# 短い文字列(インターン)
s1 = "hello"
s2 = "hello"
print(s1 == s2) # True
print(s1 is s2) # True(インターンされている)
# 動的に作成された文字列
s3 = "hel" + "lo"
s4 = "hello"
print(s3 == s4) # True
print(s3 is s4) # True(最適化により同じオブジェクト)
# スペースを含む文字列
s5 = "hello world"
s6 = "hello world"
print(s5 == s6) # True
print(s5 is s6) # 実装依存(通常はTrue)
リストと辞書での比較
1. リストでの比較
# 同じ内容のリスト
list1 = [1, 2, 3]
list2 = [1, 2, 3]
print(list1 == list2) # True(内容が同じ)
print(list1 is list2) # False(異なるオブジェクト)
# 同じリストオブジェクト
list3 = [1, 2, 3]
list4 = list3
print(list3 == list4) # True
print(list3 is list4) # True(同じオブジェクト)
# リストのコピー
list5 = [1, 2, 3]
list6 = list5.copy()
print(list5 == list6) # True(内容が同じ)
print(list5 is list6) # False(異なるオブジェクト)
2. 辞書での比較
# 同じ内容の辞書
dict1 = {"a": 1, "b": 2}
dict2 = {"a": 1, "b": 2}
print(dict1 == dict2) # True
print(dict1 is dict2) # False
# 順序が異なるが内容は同じ
dict3 = {"a": 1, "b": 2}
dict4 = {"b": 2, "a": 1}
print(dict3 == dict4) # True
print(dict3 is dict4) # False
None、True、Falseでの比較
1. Noneとの比較(重要)
# 正しいNone判定
value = None
print(value is None) # True(推奨)
print(value == None) # True(非推奨)
# カスタムクラスでの問題例
class CustomNone:
def __eq__(self, other):
return other is None
custom = CustomNone()
print(custom == None) # True(__eq__により)
print(custom is None) # False(異なるオブジェクト)
2. ブール値での比較
# ブール値の比較
flag1 = True
flag2 = True
print(flag1 == flag2) # True
print(flag1 is flag2) # True(同じオブジェクト)
# 計算結果のブール値
result1 = (5 > 3)
result2 = True
print(result1 == result2) # True
print(result1 is result2) # True
カスタムクラスでの比較
1. __eq__メソッドの実装
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if isinstance(other, Person):
return self.name == other.name and self.age == other.age
return False
# 使用例
person1 = Person("太郎", 25)
person2 = Person("太郎", 25)
person3 = person1
print(person1 == person2) # True(同じ名前と年齢)
print(person1 is person2) # False(異なるオブジェクト)
print(person1 is person3) # True(同じオブジェクト)
2. __eq__を実装しないクラス
class SimpleClass:
def __init__(self, value):
self.value = value
obj1 = SimpleClass(42)
obj2 = SimpleClass(42)
obj3 = obj1
print(obj1 == obj2) # False(同じ値だが異なるオブジェクト)
print(obj1 is obj2) # False
print(obj1 is obj3) # True(同じオブジェクト)
実践的な使用例
1. None判定での正しい使い方
def process_data(data=None):
# 正しい書き方
if data is None:
data = []
# 間違った書き方
# if data == None: # 推奨されない
return len(data)
# 使用例
print(process_data()) # 0
print(process_data([1, 2])) # 2
2. シングルトンパターンでの活用
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
# 使用例
s1 = Singleton()
s2 = Singleton()
print(s1 == s2) # True
print(s1 is s2) # True(同じインスタンス)
3. リストの変更検出
def modify_list(original_list):
new_list = original_list.copy()
new_list.append("新しい要素")
print(f"内容が同じ: {original_list == new_list}") # False
print(f"同じオブジェクト: {original_list is new_list}") # False
return new_list
# 使用例
my_list = [1, 2, 3]
modified = modify_list(my_list)
パフォーマンスの比較
1. 速度の違い
import timeit
# is演算子のテスト(高速)
def test_is():
a = None
return a is None
# ==演算子のテスト(相対的に低速)
def test_equals():
a = None
return a == None
# パフォーマンス比較
time_is = timeit.timeit(test_is, number=1000000)
time_eq = timeit.timeit(test_equals, number=1000000)
print(f"is演算子: {time_is:.6f}秒")
print(f"==演算子: {time_eq:.6f}秒")
2. 大きなオブジェクトでの比較
# 大きなリストでの比較
large_list1 = list(range(10000))
large_list2 = list(range(10000))
large_list3 = large_list1
# ==は内容をすべて比較(時間がかかる)
print(large_list1 == large_list2) # True(遅い)
# isは即座に判定(高速)
print(large_list1 is large_list2) # False(速い)
print(large_list1 is large_list3) # True(速い)
よくある間違いと対処法
1. 文字列比較での混乱
# 文字列インターンの例外
def create_string():
return "hello"
s1 = create_string()
s2 = create_string()
print(s1 == s2) # True
print(s1 is s2) # 実装依存(通常はTrue)
# 確実に異なるオブジェクトを作る
s3 = "".join(["h", "e", "l", "l", "o"])
s4 = "hello"
print(s3 == s4) # True
print(s3 is s4) # False(明確に異なる)
2. 可変オブジェクトでの誤解
def dangerous_default(items=[]):
items.append("新しい項目")
return items
# 危険な例
list1 = dangerous_default()
list2 = dangerous_default()
print(list1 == list2) # True
print(list1 is list2) # True(同じオブジェクト!)
# 正しい実装
def safe_default(items=None):
if items is None:
items = []
items.append("新しい項目")
return items
list3 = safe_default()
list4 = safe_default()
print(list3 is list4) # False(異なるオブジェクト)
3. 数値比較での注意点
# 浮動小数点数での比較
a = 0.1 + 0.2
b = 0.3
print(a == b) # False(浮動小数点の精度問題)
print(a is b) # False
# 正しい浮動小数点比較
import math
print(math.isclose(a, b)) # True
# Decimalを使った正確な計算
from decimal import Decimal
x = Decimal('0.1') + Decimal('0.2')
y = Decimal('0.3')
print(x == y) # True
print(x is y) # False(異なるオブジェクト)
デバッグとテストでの活用
1. オブジェクトの確認
def debug_comparison(obj1, obj2):
print(f"obj1: {obj1} (id: {id(obj1)})")
print(f"obj2: {obj2} (id: {id(obj2)})")
print(f"obj1 == obj2: {obj1 == obj2}")
print(f"obj1 is obj2: {obj1 is obj2}")
print(f"type(obj1): {type(obj1)}")
print(f"type(obj2): {type(obj2)}")
print("-" * 40)
# 使用例
debug_comparison([1, 2], [1, 2])
debug_comparison("hello", "hello")
debug_comparison(None, None)
2. テストでの使い分け
import unittest
class TestComparisons(unittest.TestCase):
def test_value_equality(self):
# 値の等価性をテスト
self.assertEqual([1, 2, 3], [1, 2, 3])
def test_object_identity(self):
# オブジェクトの同一性をテスト
obj = [1, 2, 3]
self.assertIs(obj, obj)
def test_none_check(self):
# None判定のテスト
value = None
self.assertIsNone(value) # is None と同等
def test_not_same_object(self):
# 異なるオブジェクトであることをテスト
list1 = [1, 2, 3]
list2 = [1, 2, 3]
self.assertEqual(list1, list2) # 値は同じ
self.assertIsNot(list1, list2) # オブジェクトは異なる
ベストプラクティス
1. 使い分けの指針
# None判定は常にisを使用
def check_none(value):
return value is None # 推奨
# ブール値判定もisを使用可能
def check_boolean(flag):
return flag is True # または単に bool(flag)
# 値の比較には==を使用
def check_equality(a, b):
return a == b # 推奨
# リストや辞書の同一性確認にはisを使用
def are_same_list(list1, list2):
return list1 is list2
2. 型チェックとの組み合わせ
def safe_comparison(obj1, obj2):
# 型チェック
if type(obj1) != type(obj2):
return False
# None判定
if obj1 is None and obj2 is None:
return True
# 値の比較
return obj1 == obj2
# 使用例
print(safe_comparison(None, None)) # True
print(safe_comparison([1, 2], [1, 2])) # True
print(safe_comparison("hello", 42)) # False
まとめ
== 演算子と is 演算子の適切な使い分け:
==演算子を使う場面
- 値の等価性を確認したい
- リストや辞書の内容を比較したい
- カスタムオブジェクトの論理的な等価性を判定したい
is演算子を使う場面
- None判定(最も重要)
- True/Falseとの直接比較
- オブジェクトの同一性を確認したい
- パフォーマンスが重要な場面
正しい使い分けにより、予期しないバグを防ぎ、効率的で読みやすいPythonコードが書けるようになります。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座



