Python3エンジニア基礎試験_公式問題集の復習③

# はじめに

「徹底攻略Python 3 エンジニア認定［基礎試験］問題集」の復習として記載しています。

https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5Python-3-%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E8%AA%8D%E5%AE%9A%EF%BC%BB%E5%9F%BA%E7%A4%8E%E8%A9%A6%E9%A8%93%EF%BC%BD%E5%95%8F%E9%A1%8C%E9%9B%86-%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BE%E3%83%93%E3%83%BC%E3%83%97%E3%83%A9%E3%82%A6%E3%83%89/dp/4295016055

# クラスの問題

次のコードについて考える。

```class.py
class Duck:
    # クラス変数familyの定義
    family = "Anatidae" # カモ科の学名
    
    # 特殊メソッド__init__の定義
    def __init__(self):
        # インスタンス変数birdsongの定義
        self.birdsong = "quack"
    # show_familyメソッドの定義
    def show_family(self):
        return f"Ducks belong to the family{self.family}."
```

* 解説

クラス定義に関する問題です。
<font color="Red">**クラス**</font>とは、データと機能を1つにまとめる仕組みのことです。新しいオブジェクトのひな型として利用できます。
クラスを使うことで、同じ構成要素（データ、機能）を持ったオブジェクトを効率的に生成できます。
クラスから生成されたオブジェクトを<font color="Red">**インスタンス**</font>と呼びます。

◎<font color="Red">**クラスを構成する要素には、クラス変数、インスタンス変数、メソッドがあります。**</font>

```書式.py
class クラス名:
    クラス変数名 = 値

    def __init__(self, 引数2, ...):
        self.インスタンス変数名 = 値
        …

    def メソッド名(self, 引数2, ...):
        # 処理内容　　
```

* <font color="Red">**クラス変数**</font>
クラスで保持する変数で、そのクラスのすべてのインスタンスで共有されます。
クラス変数はクラスの直下に定義します。通常の変数のように<font color="Red">**「変数名 = 値」**</font>の書式で記述します。

* <font color="Red">**インスタンス変数**</font>
インスタンスごとに固有の変数です。
インスタンスを初期化すための特殊メソッドである`__init__()`メソッドの中で定義します。
`__init__()`メソッドには、selfという引数を与えます。

* <font color="Red">**メソッド**</font>
クラスに定義された関数です。
メソッドの定義の仕方は関数と同じですが、第1引数に`self`を与えます。
メソッド内でクラス変数を参照する場合は、`self.`を付ける必要があります。

:::note info
参考：
`self`は、そのクラスのインスタンスを表します。
`self`はメソッドの呼び出し元で引数に渡す必要はありません。Pythonが自動的に、呼び出されたメソッドの第1引数としてインスタンスを渡してくれます。
:::

●  もう少し詳しく解説

`自己参照（self）`は、Pythonのクラス定義内で使用される特別なキーワードです。このキーワードは、そのクラスのインスタンス自体を参照するために使用されます。

クラスは、オブジェクトを作成するための設計図です。
インスタンスは、そのクラスの設計に基づいて作成された実際のオブジェクトです。例えば、クラスが「Car（自動車）」を表す場合、インスタンスは「my_car（私の車）」や「your_car（あなたの車）」などといった具体的な車を表すことができます。

クラス内のメソッドは、そのクラスに関連する動作を定義します。メソッドは通常、引数を受け取りますが、その最初の引数として`「self」`を受け取ります。これはPythonの慣例であり、通常`「self」`という名前を使用しますが、別の名前を使用することも可能です。

`「self」`をメソッドの第1引数として指定する必要はありません。Pythonは、メソッドを呼び出す際に自動的にインスタンスを`「self」`として渡してくれます。これにより、メソッド内で`「self」`を使用して、そのインスタンスの属性や他のメソッドにアクセスすることができます。

```example.py
class Car:
    def __init__(self, brand):
        self.brand = brand

    def start_engine(self):
        print("The", self.brand, "car engine is started.")

my_car = Car("Toyota")
my_car.start_engine()
# The Toyota car engine is started.
```

上記の例では、`「Car」`というクラスが定義されています。そのクラスには`「init」`と`「start_engine」`という2つのメソッドがあります。`「init」`メソッドはインスタンスの初期化を行い、引数として`「self」`と`「brand」`を受け取ります。`「start_engine」`メソッドは、車のエンジンを起動するためのメソッドであり、引数として`「self」`を受け取りません。

`「my_car」`という名前の`「Car」`クラスのインスタンスが作成されています。インスタンスが作成される際には、`「init」`メソッドが呼び出され、引数として`「self」`には作成されたインスタンス自体が渡されます。また、引数`「brand」`には文字列`「Toyota」`が渡されます。

その後、`「start_engine」`メソッドが呼び出されますが、
引数として`「self」`を指定する必要はありません。Pythonは自動的にインスタンスを`「self」`として渡します。

したがって、`my_car.start_engine()`の呼び出しでは、`start_engine`メソッドには明示的に引数を渡す必要はありません。インスタンス自体が`「self」`として渡されます。

`start_engine`メソッド内のコードでは、`self.brand`を使用してインスタンスの属性にアクセスしています。`self.brand`は、`__init__`メソッド内で設定されたインスタンスの`brand`属性を参照します。その結果、`start_engine`メソッドの実行結果は、`「The Toyota car engine is started.」`と表示されます。

# クラスの問題

次のコードについて考える。

```class.py
class Duck:
# Duckクラスをインスタンス化するための記述は下記のようにする
# duck = Duck()
```

* 解説
クラスのインスタンス化に関する問題です。
<font color="Red">**インスタンス化**</font>は、関数の実行と同様に<font color="Red">**「変数名 = クラス()」**</font>の書式で行います。
また、次のように`__init__()`メソッドを定義することで、インスタンス化時の処理を記述できます。
このメソッドの第1引数の`self`は、そのクラスのインスタンスを表す特殊な引数です。
第2引数以降は、呼び出し元から渡される引数をそのまま受け取ります。

```class.py
class Duck:
    def __init__(self, birdsong):
        # インスタンス変数birdsongの値を、引数birdsongの値で初期化する
        self.birdsong = birdsong

    def sing(self):
        return self.birdsong

duck = Duck("quack") 
print(duck.sing())
# quack
```

* コードの解説
1. `Duck`クラスが定義されます。このクラスは、鳥の鳴き声を表すインスタンス変数と、その鳴き声を返す`sing`メソッドを持っています。
1. `Duck`クラスのインスタンスを作成します。`duck = Duck("quack")`という行で、`Duck`クラスの`コンストラクタ（__init__メソッド）`が呼び出されます。引数として`"quack"`が渡され、新しい`Duck`インスタンスが作成されます。インスタンス変数`birdsong`は、引数の値である`"quack"`で初期化されます。
1. `duck.sing()`を呼び出します。これにより、`Duck`クラスの`sing`メソッドが実行されます。`sing`メソッド内では、`self.birdsong`が返されます。`self`は呼び出し元のインスタンスであり、`self.birdsong`はインスタンス変数`birdsong`の値を参照します。
1. `print(duck.sing())`によって、`duck.sing()`の結果が表示されます。この場合、インスタンス変数`birdsong`の値である`"quack"`が表示されます。

# クラスの問題

次のコードについて考える。

```class.py
class Duck:
    def __init__(self):
        self.birdsong = "quack"

    def change_birdsong(self, birdsong):
        self.birdsong = birdsong

    def show_birdsong(self):
        print(self.birdsong)
        self.change_birdsong("ga-ga-")
        print(self.birdsong)
Duck().show_birdsong()
# quack
# ga-ga-
```

* 解説
メソッド内で、同一クラスに定義された他のメソッドを呼び出す方法に関する問題です。
<font color="Red">**他のメソッドを呼び出す際は、メソッド名の先頭に`.self`を付けます。**</font>