3秒でわかる
クラスという設計図をもとにしてメモリ上へ作られた実体。同じ設計図から作っても、それぞれが独自の値を持つ別物として動きます。
もう少し詳しく
どういうものか
インスタンスは、クラスを設計図として実際に生成された 1 つの実体です。クラスは「どんな属性と操作を持つか」を定義するだけで、値は持ちません。new や呼び出しによってインスタンスが作られた時点で、メモリ上に領域が確保され、そこに固有の値が入ります。
同じクラスから 2 つ作れば、属性の構成は同じでも中身は別々です。片方の値を変えても、もう片方には影響しません。
なぜ必要か
利用者ごと、注文ごと、接続ごとに別々の状態を持たせたいとき、その数だけ変数を並べる方法では破綻します。user1_name、user2_name と増やしていけば、処理も人数分書くことになります。同じ形の入れ物を必要な数だけ複製できる仕組みがあれば、処理は 1 つ書くだけで済みます。インスタンスはそのための単位です。
具体例
class Cat:
kind = "ネコ科" # クラス変数(全インスタンスで共有)
def __init__(self, name, age):
self.name = name # インスタンス変数(個別)
self.age = age
def introduce(self):
return f"{self.name}({self.age}歳)"
tama = Cat("タマ", 3)
mike = Cat("ミケ", 5)
print(tama.introduce()) # タマ(3歳)
print(mike.introduce()) # ミケ(5歳)
print(tama is mike) # False (別の実体)
print(tama.kind, mike.kind) # ネコ科 ネコ科 (共有)tama と mike は同じクラスから作られていますが、name と age はそれぞれが持っています。
つまずきやすいところ
クラス変数とインスタンス変数の混同が最も多い落とし穴です。とくに def __init__(self, items=[]) のように可変オブジェクトを既定値にすると、その リストは関数定義時に 1 つだけ作られ、全インスタンスで共有されます。1 匹目に追加した要素が 2 匹目にも入っている、という不可解な挙動になります。既定値は None にして、初期化の中で新しいリストを作ります。
Java では、インスタンスを作らずにクラス名から呼べるのは static なメンバーだけです。main から直接インスタンスメソッドを呼ぼうとしてコンパイルエラーになるのは、実体がまだ無いためです。
代入は複製ではない点も要注意です。b = a としても新しいインスタンスは作られず、同じ実体を 2 つの名前で指しているだけです。
似た用語との違い
| 用語 | 内容 |
|---|---|
| クラス | 設計図。属性と操作の定義 |
| インスタンス | 設計図から作られた実体 |
| オブジェクト | 実体を指す一般語。インスタンスとほぼ同義で使われる |
覚え方
クラスはたい焼きの型、インスタンスは焼き上がったたい焼き。型は 1 つでも、中身のあんこは 1 個ずつ別に入っています。