Pythonでプログラミングを学んでいると、「クラス」や「インスタンス」という言葉が出てきます。
この記事では、Pythonのクラスとインスタンスの基本について、
- クラスとインスタンスの違い
-
self
や__init__
の意味 - インスタンス変数とクラス変数の違い
- スコープ、特殊メソッド、継承の基本
など、つまずきやすいポイントを含めて整理してみました。
クラスとインスタンスとは?
クラスは「設計図」、インスタンスはその設計図から作られた「実体」です。
- クラス:モノの設計図(例:人、車、商品 などの「型」)
- インスタンス:その設計図から作られた具体的な「実体」
例えば、「Employee(社員)」というクラスから、実際の社員データを生成したものがインスタンスです。
クラスの基本構文
クラスは class
キーワードを使って定義し、その中にメソッドを記述します。
class クラス名:
def メソッド名(self):
処理内容
例:
class Employee:
def greet(self):
print("こんにちは!")
e = Employee()
e.greet() # → こんにちは!
インスタンスの作り方(クラスから実体を生成する)
クラスを定義しただけでは、まだ「設計図」ができただけです。
実際に使うには、そのクラスからインスタンス(実体)を作成する必要があります。
変数名 = クラス名()
このように、クラス名のあとに ()
をつけて呼び出すことで、Pythonはそのクラスのインスタンスを作り、新しく生成されたオブジェクトを変数に代入します。
例:
class Dog:
def bark(self):
print("ワン!")
d = Dog() # ← クラスからインスタンスを作成
d.bark() # → ワン!
このとき、Dog()
のようにクラスを呼び出すと、Pythonは自動的に __init__()
という特別なメソッドを呼び出して、初期化処理を行います。
もし __init__()
に引数があれば、それに応じて値を渡すこともできます。
class User:
def __init__(self, name):
self.name = name
u = User("Taro")
print(u.name) # → Taro
このようにして、クラスの設計に基づいて、具体的な「インスタンス=使えるオブジェクト」を作ることができます。
インスタンス変数とクラス変数の違い
クラス変数はクラス全体で共有され、インスタンス変数は個々のインスタンスに属します。
class Sample:
class_var = "クラス変数"
def __init__(self):
self.instance_var = "インスタンス変数"
- クラス変数:全インスタンスで共通(
Sample.class_var
) - インスタンス変数:各インスタンスごとに固有(
x.instance_var
)
__init__
メソッドとは?
インスタンス生成時に最初に呼び出されるメソッドで、初期化処理を記述します。
class User:
def __init__(self, name):
self.name = name
u = User("Taro")
print(u.name) # → Taro
self
ってなに?
self
は「自分自身のインスタンス」を指すキーワードで、インスタンスの属性やメソッドにアクセスするために使います。
インスタンスを使った属性の追加・変更
__init__
メソッドの外からでも、属性を追加・変更することが可能です。
class Item:
pass
x = Item()
x.name = "りんご"
print(x.name) # → りんご
ただし、__init__
の中で定義しておく方が、コードの可読性や意図が明確になります。
ローカル変数との違い
ローカル変数は関数内でのみ使える一時的な変数で、インスタンス変数とは異なります。
class Test:
def show(self):
data = 100
return data
def set(self):
self.data = 200 # インスタンス変数
t = Test()
t.set()
print(t.data) # → 200
ローカル変数は t.data
ではアクセスできません。
スコープ:global
とnonlocal
変数の有効範囲(スコープ)を理解することは、予期せぬ動作を防ぐのに重要です。
Pythonのスコープには以下の4つがあります:
- Local(関数内)
- Enclosing(外側の関数のスコープ)
- Global(モジュールレベル)
- Built-in(組み込み名前空間)
global
を使うと、関数の中からモジュール全体の変数を上書きできます。
spam = "global"
def update():
global spam
spam = "updated"
update()
print(spam) # → updated
nonlocal
は、ネストされた関数の中から、1つ外側の関数内の変数にアクセス・更新したいときに使います。
def outer():
msg = "outer"
def inner():
nonlocal msg
msg = "updated"
inner()
print(msg) # → updated
__str__()
と __repr__()
の違い
オブジェクトの出力内容を整えることで、デバッグやログ出力をより分かりやすくできます。
-
__str__()
:人間が読みやすい文字列を返す -
__repr__()
:開発者向けの表現を返す(オブジェクトの情報を詳しく)
class Book:
def __init__(self, title):
self.title = title
def __str__(self):
return f"Title: {self.title}"
def __repr__(self):
return f"Book(title={self.title!r})"
b = Book("Python入門")
print(b) # → Title: Python入門(__str__() が呼ばれる)
print(str(b)) # → Title: Python入門(__str__() が呼ばれる)
print(repr(b)) # → Book(title='Python入門')(__repr__() が呼ばれる)
クラスの継承
クラスの再利用や拡張には「継承」を使います。親クラス(スーパークラス)を元に、新しい子クラス(サブクラス)を作成できます。
クラスを継承すると何が引き継がれる?
クラスを継承すると、親クラスが持っている
- メソッド(関数)
- 変数(属性)
を子クラスでそのまま使うことができます。
子クラスで何も書き換えなければ、親クラスの動作がそのまま適用されます。
例:
class Animal:
def __init__(self):
self.type = "動物"
def speak(self):
print("鳴き声")
class Cat(Animal):
pass # 何も書き換えていない
c = Cat()
print(c.type) # → 動物(親の属性をそのまま使える)
c.speak() # → 鳴き声(親のメソッドをそのまま使える)
オーバーライド(override)とは?
**オーバーライド(override)**とは、親クラスで定義されているメソッドを、子クラスで上書きして新しく定義し直すことをいいます。
これによって、子クラスで独自の振る舞いを持たせることができます。
例(super()を使わないオーバーライド):
class Animal:
def speak(self):
print("動物の鳴き声")
class Cat(Animal):
def speak(self): # オーバーライド
print("ニャー")
c = Cat()
c.speak() # → ニャー
このように、親クラスに speak()
というメソッドがあっても、子クラスで同じ名前のメソッドを定義し直すと、子クラスのメソッドが優先されます。
super()
を使ったオーバーライド
子クラスでオーバーライドするときに、親クラスの元の処理も併せて実行したい場合には、super()
を使います。
super()
は、子クラスでオーバーライドしたメソッドの中から、親クラスの元の処理を呼び出したいときに使います。
なお、親クラスのメソッドや変数をそのまま使うだけなら、super()
を使わずに呼び出せます。
例(super()を使ったオーバーライド):
class Animal:
def __init__(self):
print("Animalの初期化")
def speak(self):
print("動物の鳴き声")
class Dog(Animal):
def __init__(self):
super().__init__() # 親の初期化も呼ぶ
print("Dogの初期化")
def speak(self):
super().speak() # 親のspeak()も呼ぶ
print("ワン!")
d = Dog()
d.speak()
出力:
Animalの初期化
Dogの初期化
動物の鳴き声
ワン!
super()
はいつ必要?
シチュエーション |
super() 必要? |
説明 |
---|---|---|
親のメソッドや変数を普通に使うだけ | ❌ 不要 | 親クラスを継承していれば、そのまま使える |
子クラスでオーバーライドして、さらに親の処理も使いたい | ✅ 必要 | 子クラスで新しい動きを追加しつつ、親の動きも引き継ぎたいとき |
親クラスの __init__() を呼びたいとき |
✅ 必要 | 子クラスで初期化処理を追加したいとき、親の初期化もきちんと呼び出す必要がある |
super()使用の簡単な例:
class Parent:
def greet(self):
print("Hello from Parent!")
class Child(Parent):
def greet(self):
super().greet()
print("Hello from Child!")
c = Child()
c.greet()
出力:
Hello from Parent!
Hello from Child!
まとめ
- クラス=設計図、インスタンス=実体
- インスタンス変数は
self.変数名
で作る - 外から
インスタンス.変数名 = 値
として追加もできる -
__init__
は初期化処理、self
は自分自身を指す -
__str__()
や__repr__()
で見た目の出力を制御できる -
global
とnonlocal
でスコープを正しく理解しよう - クラスは継承によって再利用・拡張ができる(
super()
を使って親の処理を呼び出せる)
クラスやインスタンスは、Pythonの中でも最初につまずきやすいところでしたが、実際に手を動かして動作を確認すると、だんだん見えてくる部分がありました。
今後も継承やオーバーライドを使う機会が増えてくると思うので、そのたびに super() やスコープの扱いなどを丁寧に見直していこうと思います。