【Python初心者】クラスとインスタンスの基本のまとめ

Pythonでプログラミングを学んでいると、「クラス」や「インスタンス」という言葉が出てきます。

この記事では、Pythonのクラスとインスタンスの基本について、

- クラスとインスタンスの違い
- `self` や `__init__` の意味
- インスタンス変数とクラス変数の違い
- スコープ、特殊メソッド、継承の基本

など、つまずきやすいポイントを含めて整理してみました。


## クラスとインスタンスとは？
クラスは「設計図」、インスタンスはその設計図から作られた「実体」です。

- **クラス**：モノの設計図（例：人、車、商品 などの「型」）
- **インスタンス**：その設計図から作られた具体的な「実体」

例えば、「Employee（社員）」というクラスから、実際の社員データを生成したものがインスタンスです。

## クラスの基本構文
クラスは `class` キーワードを使って定義し、その中にメソッドを記述します。

```python
class クラス名:
    def メソッド名(self):
        処理内容
```

例：
```python
class Employee:
    def greet(self):
        print("こんにちは！")

e = Employee()
e.greet()  # → こんにちは！
```
## インスタンスの作り方（クラスから実体を生成する）

クラスを定義しただけでは、まだ「設計図」ができただけです。  
実際に使うには、そのクラスから**インスタンス（実体）を作成**する必要があります。

```python
変数名 = クラス名()
```

このように、クラス名のあとに `()` をつけて呼び出すことで、Pythonはそのクラスのインスタンスを作り、新しく生成されたオブジェクトを変数に代入します。

例：

```python
class Dog:
    def bark(self):
        print("ワン！")

d = Dog()      # ← クラスからインスタンスを作成
d.bark()       # → ワン！
```

このとき、`Dog()` のようにクラスを呼び出すと、Pythonは自動的に `__init__()` という特別なメソッドを呼び出して、初期化処理を行います。  
もし `__init__()` に引数があれば、それに応じて値を渡すこともできます。

```python
class User:
    def __init__(self, name):
        self.name = name

u = User("Taro")
print(u.name)  # → Taro
```

このようにして、クラスの設計に基づいて、具体的な「インスタンス＝使えるオブジェクト」を作ることができます。
## インスタンス変数とクラス変数の違い
クラス変数はクラス全体で共有され、インスタンス変数は個々のインスタンスに属します。

```python
class Sample:
    class_var = "クラス変数"

    def __init__(self):
        self.instance_var = "インスタンス変数"
```

- クラス変数：全インスタンスで共通（`Sample.class_var`）
- インスタンス変数：各インスタンスごとに固有（`x.instance_var`）

## `__init__`メソッドとは？
インスタンス生成時に最初に呼び出されるメソッドで、初期化処理を記述します。

```python
class User:
    def __init__(self, name):
        self.name = name

u = User("Taro")
print(u.name)  # → Taro
```

## `self`ってなに？
`self` は「自分自身のインスタンス」を指すキーワードで、インスタンスの属性やメソッドにアクセスするために使います。

## インスタンスを使った属性の追加・変更
`__init__` メソッドの外からでも、属性を追加・変更することが可能です。

```python
class Item:
    pass

x = Item()
x.name = "りんご"
print(x.name)  # → りんご
```

ただし、`__init__` の中で定義しておく方が、コードの可読性や意図が明確になります。

## ローカル変数との違い
ローカル変数は関数内でのみ使える一時的な変数で、インスタンス変数とは異なります。

```python
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` を使うと、関数の中からモジュール全体の変数を上書きできます。

```python
spam = "global"

def update():
    global spam
    spam = "updated"

update()
print(spam)  # → updated
```

`nonlocal` は、ネストされた関数の中から、1つ外側の関数内の変数にアクセス・更新したいときに使います。

```python
def outer():
    msg = "outer"
    def inner():
        nonlocal msg
        msg = "updated"
    inner()
    print(msg)  # → updated
```

## `__str__()` と `__repr__()` の違い
オブジェクトの出力内容を整えることで、デバッグやログ出力をより分かりやすくできます。

- `__str__()`：人間が読みやすい文字列を返す
- `__repr__()`：開発者向けの表現を返す（オブジェクトの情報を詳しく）

```python
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__() が呼ばれる）
```

## クラスの継承
クラスの再利用や拡張には「継承」を使います。親クラス（スーパークラス）を元に、新しい子クラス（サブクラス）を作成できます。

### クラスを継承すると何が引き継がれる？

クラスを継承すると、親クラスが持っている

- **メソッド**（関数）
- **変数（属性）**

を子クラスでそのまま使うことができます。  
子クラスで何も書き換えなければ、親クラスの動作がそのまま適用されます。

#### 例：

```python
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()を使わないオーバーライド）：

```python
class Animal:
    def speak(self):
        print("動物の鳴き声")

class Cat(Animal):
    def speak(self):  # オーバーライド
        print("ニャー")

c = Cat()
c.speak()  # → ニャー
```

このように、親クラスに `speak()` というメソッドがあっても、子クラスで同じ名前のメソッドを定義し直すと、**子クラスのメソッドが優先されます**。


### `super()` を使ったオーバーライド

子クラスでオーバーライドするときに、**親クラスの元の処理も併せて実行したい場合**には、`super()` を使います。

`super()` は、**子クラスでオーバーライドしたメソッドの中から、親クラスの元の処理を呼び出したいときに使います。**  
なお、親クラスのメソッドや変数をそのまま使うだけなら、`super()`を使わずに呼び出せます。

#### 例（super()を使ったオーバーライド）：

```python
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()使用の簡単な例：

```python
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() やスコープの扱いなどを丁寧に見直していこうと思います。