Pythonのisによるオブジェクト同一性の判定と使い方をわかりやすく解説

スポンサーリンク
スポンサーリンク
amazon
スマイルSALE
--:--:--
ad. 価格範囲を指定して商品を探せます

isの概要

オブジェクトの同一性(実体の同一)判定 Python予約語

is

概要 is(イズ)は、比較対象となる2つの変数が、値の良し悪しに関わらず「メモリ上の全く同じ場所にある、全く同じ実体(オブジェクト)」を指し示しているかどうか(同一性)を判定するための比較演算子です。

わかりやすく説明 is は、プログラムにおける「双子(別物だけどそっくり)か、それとも本人(同一人物)か」を確かめるためのキーワードです。見た目のデータや値がどれほど完全に一致していても、メモリ上の格納場所(住所)が別々であれば is の審査は False になります。逆に、同じ実体を複数の名前で使い回している(参照している)場合には True と判定されます。

  • 2つのオブジェクトをコンピュータが識別するためのシリアル番号(固有のメモリアドレス)である id() の値が合致するかどうかを内部で判定しています。
  • 中身のデータを比較する ==(等価性)とは完全に異なる役割を持っており、実務ではデータの有無を表す None の判定の特等席として機能します。
  • プログラム全体でただ1つしか存在しないことが保証されている特殊なデータ(None, True, False などのシングルトン)を最速かつ最も安全にチェックする手段です。

isの考え方をイメージで理解

isの基本的な使い方

あるリスト a を作り、それをそのまま別の変数 b に「参照(リモコン)をコピー」したとき、両者が全く同じ実体を指しているかを検証する例です。

# is を使ったオブジェクトの同一性判定
a = [1, 2, 3]
b = a  # aの「実体」が置いてあるメモリの場所をそのままbに教える(参照渡し)

print(a is b)  # 結果: True(全く同じ実体)
print(id(a) == id(b))  # 内部ではこれと同じメモリアドレスの一致を調べています
  • b = a の処理は、データを複製したのではなく、1つのデータに対して「a という名前」と「b という名前」の2本のアクセスルート(参照)を用意した状態になるため、isTrue を返します。

isと==の違い

「見た目(中身のデータ)が同じ」であることと、「コンピュータにとって同じ個体である」ことの決定的な違いが判る、最も分かりやすい例です。

# is と == の明確な違い
a = [1, 2, 3]
b = [1, 2, 3] # 新しくメモリ上の別の場所に、同じ中身のリストを作成

print(a == b)  # 結果: True (中身の「1, 2, 3」という値が同じなので合格)
print(a is b)  # 結果: False(中身は同じだが、メモリ上の住所が違う別オブジェクトなので不合格)
  • 他言語でいう「値渡し」と「参照渡し」の理解に直結する部分です。リストなどの変更可能なオブジェクト(ミュータブル)を新しく定義すると、必ず新しいメモリアドレスが割り当てられます。

isを使ったNoneの判定(実務での最頻出パターン)

Python実務において is が最も多く使われ、開発の現場で鉄則とされている「データが空、または存在しない状態(None)」を判定する書き方です。

# None の安全な判定
x = None

if x is None:
    print("x は何もデータを持っていない『None』という状態です")
  • None はPythonシステム全体の中で絶対に1つしか作られないという強力なルールがあるため、== None ではなく is None を使うことで、最速かつ他のオブジェクトの誤作動(__eq__のオーバーライドバグなど)に巻き込まれずに判定できます。

isの応用例(シングルトンオブジェクトの判定)

None と同様に、論理値である TrueFalse もPythonのシステム内部に1個ずつしか存在しないため、is を使ってオブジェクトが同一であることを瞬時に見破ることができます。

# シングルトンオブジェクトの判定
x = True
y = True

print(x is y)  # 結果: True(同じTrueオブジェクトの場所を指している)

isの使用上の注意点

  • 数値や文字列の比較に is を使ってはいけない(バグの温床):初心者が最も陥りやすい罠が、数値や文字列の一致判定に is を使ってしまうことです。Pythonはパフォーマンス向上のため、特定の小さな整数(-5から256まで)や短い文字列をメモリ内部で勝手に使い回す(キャッシュする)という裏の仕組みを持っています。このため、たまたま isTrue になることがあっても、値が大きくなった瞬間に突然 False に切り替わり、予測不能なバグを生み出す原因になります。値の比較は必ず == を徹底してください。
    # 【非常に危険な挙動の例】
    num1 = 100
    num2 = 100
    print(num1 is num2)  # 結果: True (100はPythonが内部キャッシュしているため同一とみなされる)
    
    num3 = 1000
    num4 = 1000
    print(num3 is num4)  # 結果: False(1000はキャッシュ対象外のため、別の個体として生成されてしまう!)
    # ※値の比較には絶対に「is」ではなく「==」を使ってください!
  • ミュータブルなオブジェクト(リストや辞書)の破壊的変更の影響isTrue である2つの変数は、実体が1つしかありません。そのため、片方の変数を書き換えると、もう片方の変数の内容も自動的に、同時に書き換わります。これはデータ構造を扱う上でバグを引き起こしやすいため、別々のデータとして扱いたい場合は copy.deepcopy() などを使用して、メモリ上の実体ごと複製(ディープコピー)する必要があります。

isのよくある質問

Q: `if x is not None:` という書き方をよく見かけますが、これは何ですか?
A: 「変数の値が、None(空っぽ)ではないとき」を判定する、Pythonの非常に美しく洗練された標準的なイディオム(定型文)です。 if not x is None: と書くよりも、英文として(x is not None)自然に読めるため、可読性を重視するPythonの文化において最も推奨される記述スタイルとなっています。

# 実務で毎日使う、Noneの回避チェック
if user_input is not None:
    print("有効なデータが入っています")
Q: `==` の代わりに全部 `is` を使ったほうが、処理スピードが速いと聞きましたが本当ですか?
A: 確かに処理速度の面だけで言えば、is はメモリアドレスの数字の羅列を1回比較するだけなので、オブジェクトの中身を深くまで精査する == よりも圧倒的に高速です。 しかし、前述の通り数値や文字列に対して is を使うと、Pythonの内部キャッシュの影響で予期せぬ判定漏れや致命的な計算バグを引き起こします。速度のために安全性を犠牲にするのは実務のプログラミングでは言語道断です。「None、True、Falseへの判定だけが is の領土であり、それ以外のデータの比較はすべて == に任せる」と厳格にルールを切り分けてください。

まとめ

is は、データの価値そのものではなく、そのオブジェクトが配置されているメモリ空間の「物理的な実体の同一性」を厳格に見極めるための演算子です。

  • 2つの変数が全く同じメモリアドレス(オブジェクト)を指しているときにのみ True を返す。
  • 中身の「値」が等しいかを調べる == とは文法的な役割が180度異なるため、混同は禁物。
  • 実務における主戦場は is Noneis not None であり、これらを使うことで最も安全で高速な条件分岐を保証できる。

Pythonのメモリ管理の仕組み(参照渡しや整数のキャッシュ仕様)を深く理解し、is== を完全にコントロールできるようになることで、裏でデータが勝手に書き換わるような事故のない、スマートで信頼性の高いPythonコードを記述できるようになりましょう。