pythonのクラスについて勉強する

2024/04/27

CustomTkinter python プログラミング

 今までpythonでプログラムを作る際は小規模なプログラムしか書いておらず、関数のみでプログラミングを行っていました。

現在の私の状況ではクラスは使わなくても実装が出来るのですが、今後のために今回のタイミングで勉強していきます。

クラスは少し複雑な概念なので、この記事の目標としてはなんとなくクラスについて理解が出来るようになるすることを目標にします。(勉強していく中で間違いがあれば都度直していきます。)

クラス/メンバ(アトリビュート)/メソッド/インスタンス/コンストラクタについて

初めてクラスを勉強する際に思ったのはいろいろな用語が出てきており、初学者の自分にとっては用語が分からず理解が難しかったです。まず初めに用語について具体例を交えながら整理します。

クラスとは一言で言うと変数と関数をまとめたもののことを言います。
クラスの中では変数の事をメンバ(サイトによってはアトリビュートという記載もしてます)といい、関数のことをメソッドといいます。

関係を図に示すと以下のようになります。

クラスの役割としては共通仕様を持った設計図を作るイメージです。例えば今回車を作るクラスを作るとします。車を作る際にパラメーターとして例えばボディーの色や乗車人数、馬力などを決める必要があります。関数(機能)として走る、曲がる、止まる機能が必要です。

これらのパラメーターや関数はスポーツカーや電気自動車トラックに至るまですべての車に共通しているものとなってます。

毎回これらのパラメーターの定義や機能の実装をするのは効率が悪いため、下記図のようにテンプレート化していろいろな種類の車を作れるようにするのがクラスの目的です。

この設計図を元に実体化することをインスタンスといいます。ただ、こちらは表記ゆれが多くオブジェクト化という人もいます。どちらが正しいかは不明ですが、興味がある方はこちらの記事を参照お願いします。

続いてコンストラクタについてです。コンストラクタはインスタンスが生成される際に実行される特殊なメソッドのことを言います。今回の車の例で示すのが難しいのですが、メソッドの一部である程度で理解していただければと思ってます。

クラス/メンバ/コンストラクタのサンプルコード

それでは実際にクラス、メンバ、メソッドのサンプルコードを書いていきます。

まずはクラスの定義です。クラスは下記のように定義します。ここでは先ほどの例にならって自動車を作るクラスを作ります。
class Car:  # 自動車の作るクラス
    # クラスの中身を記載
少し細かいですが、pythonにはPEP8と呼ばれるコーディングルールが存在します。
PEP8ではクラスの名前はCapWord方式で定義することを推奨しています。CapWord方式とは簡単にいうと単語の先頭を大文字にする方式です。複数の単語でつなげる場合はAutoDriveのような名前になります。

話を元に戻しますが、続いてコンストラクタ部分を記載していきます。コンストラクタは関数の定義と同じでdefで記載し、関数名を"__init__"にします。
# クラスの定義
class Car:  # 自動車の作るクラス

    def __init__(self, horsepower, color, passengers, energy):  # コンストラクタの記述(慣例的に第一引数は"self"とする)
        self.horsepower = horsepower  # 馬力の指定
        self.color = color  # 色の指定
        self.passengers = passengers  # 乗車人数の指定
        self.energy = energy
        print("馬力:%s" % (self.horsepower))
        print("色:%s" % (self.color))
        print("乗車人数:%s" % (self.passengers))
        print("動力源:%s" % (self.energy))
先ほど関数の定義と同じといいましたが、注意点が2つあります。
  1. 第一引数をselfにしなくてはいけない
  2. 変数をクラス内で呼び出す場合は"self.変数名"で記載しないといけない
上記2点以外は普通の関数定義と同じルールでできます。また、このサンプルプログラムではコンストラクタ部でメンバに値を代入する処理を記述してます。

メソッドのサンプルコード

続いて先ほどのコードにメソッドのコードを追加していきます。メソッドもコンストラクタと同様のルールで記載していきます。
# クラスの定義
class Car:  # 自動車の作るクラス

    def __init__(self, horsepower, color, passengers, energy):  # コンストラクタの記述(慣例的に第一引数は"self"とする)
        self.horsepower = horsepower  # 馬力の指定
        self.color = color  # 色の指定
        self.passengers = passengers  # 乗車人数の指定
        self.energy = energy
        print("馬力:%s" % (self.horsepower))
        print("色:%s" % (self.color))
        print("乗車人数:%s" % (self.passengers))
        print("動力源:%s" % (self.energy))

    def run(self):  # 走るメソッドの記載(メソッドも慣例的に第一引数に"self"を入れる)
        print("run function")

    def stop(self):  # 止まるメソッドの記載
        print("stop function")

    def turns(self):  # 曲がるメソッドの記載
        print("turns function")
今回は先ほどの例に記載した走る、曲がる、止まる関数を定義します。(といっても中身はただのプリント文ですが、、、)

インスタンス化について

これで設計図が作られたので、ここではインスタンス化して実体にしていきます。
インスタンス化は下記のようにクラスを呼び出すだけです。
car1 = Car(500, "red", 2, "ガソリン")
ここでは下記のようにスポーツカーと乗用車の2種類の車を作ってみます。メソッドはともに同じでメンバだけ変えています。

インスタンス化のサンプルコード

それでは具体的にコードを追記していきます。
# クラスの定義
class Car:  # 自動車の作るクラス

    def __init__(self, horsepower, color, passengers, energy):  # コンストラクタの記述(慣例的に第一引数は"self"とする)
        self.horsepower = horsepower  # 馬力の指定
        self.color = color  # 色の指定
        self.passengers = passengers  # 乗車人数の指定
        self.energy = energy
        print("馬力:%s" % (self.horsepower))
        print("色:%s" % (self.color))
        print("乗車人数:%s" % (self.passengers))
        print("動力源:%s" % (self.energy))

    def run(self):  # 走るメソッドの記載(メソッドも慣例的に第一引数に"self"を入れる)
        print("run function")

    def stop(self):  # 止まるメソッドの記載
        print("stop function")

    def turns(self):  # 曲がるメソッドの記載
        print("turns function")


class AutoDrive(Car):
    def autodrive(self):  # 自動運転メソッド
        print("AI Drivemode")    


print("car1")
car1 = Car(500, "red", 2, "ガソリン")  # スポーツカーをインスタス化
car1.run()
car1.stop()
car1.turns()


print("\ncar2")
car2 = Car(100, "green", 4, "ガソリン")  # 乗用車をインスタンス化
car2.run()
car2.stop()
car2.turns()
上記コードで1点補足ですが、インスタンスのメソッドを呼び出す場合はインスタンス名.メソッド名の形で呼び出すことが出来ます。上記コードはそれぞれのインスタンスのメソッドを呼び出してます。


こちらを実行した結果が下記の通りです。性能が異なるが、同じ機能を持った2種類の車が作れたことが分かります。このようにクラスにすることで似たような機能を持つもの簡単に沢山作ることが出来るようになります。

継承について

続いて継承についてです。継承は名前の通り、既存のクラスの機能を別のクラスに継承することが出来ます。例えば先ほどの自動車クラスに自動運転メソッドを追加したい場合などに使います。

ここで、継承元のクラスのことを親クラス(基底クラスとも記載している文献もあります)といい、継承先のメソッドのことを子クラス(派生クラスと記載している文献もあります)といいます。

下記画像は赤字で追加したメソッドが子クラスで新たに定義したメソッドでそれ以外は親クラスの内容を引き継いでます。

継承のサンプルコード

それでは具体的に継承のコードを書いていきます。継承のやり方は子クラスの宣言時に引数に親クラスを記述するだけです。下記例では子クラスであるAutoDriveクラスがCarクラスの内容を継承して、新たにautodriveメソッドを定義しています。
class AutoDrive(Car):
    def autodrive(self):  # 自動運転メソッド
        print("AI Drivemode")  
上記記述をサンプルプログラムに追加します。

# クラスの定義
class Car:  # 自動車の作るクラス

    def __init__(self, horsepower, color, passengers, energy):  # コンストラクタの記述(慣例的に第一引数は"self"とする)
        self.horsepower = horsepower  # 馬力の指定
        self.color = color  # 色の指定
        self.passengers = passengers  # 乗車人数の指定
        self.energy = energy
        print("馬力:%s" % (self.horsepower))
        print("色:%s" % (self.color))
        print("乗車人数:%s" % (self.passengers))
        print("動力源:%s" % (self.energy))

    def run(self):  # 走るメソッドの記載(メソッドも慣例的に第一引数に"self"を入れる)
        print("run function")

    def stop(self):  # 止まるメソッドの記載
        print("stop function")

    def turns(self):  # 曲がるメソッドの記載
        print("turns function")


class AutoDrive(Car):
    def autodrive(self):  # 自動運転メソッド
        print("AI Drivemode")    




print("\ncar2")
car2 = Car(100, "green", 4, "ガソリン")  # 乗用車をインスタンス化
car2.run()
car2.stop()
car2.turns()
print("\ncar3")
car3 = AutoDrive(100, "green", 4, "ガソリン")  # Carクラスを継承したAutoDriveクラスをインスタンス化
car3.run()
car3.stop()
car3.turns()
car3.autodrive()
car1とcar2は似たような処理なので、ここでは削除しました。このプログラムを実行した結果は次の通りです。

car3はAutoDriveクラスをインスタンス化したもので、AutoDriveクラス内にはrunメソッドなどは定義していなかったですが、Carクラスで定義されたメソッドを呼び出して実行できていることが分かります。

オーバーライドについて

続いてオーバーライドです。オーバーライドはメソッドを上書きするようなものです。親クラスを継承した子クラス内に親クラスと同じ名前のメソッドを定義すると子クラスで定義されたメソッドに上書きすることが出来ます。

ここでは以下のように"止まる関数"を"止まる関数 Wtih 回生ブレーキ"に変更します。

オーバーライドのサンプルコード

それでは具体的にオーバーライドのサンプルコードを書いていきます。
# クラスの定義
class Car:  # 自動車の作るクラス

    def __init__(self, horsepower, color, passengers, energy):  # コンストラクタの記述(慣例的に第一引数は"self"とする)
        self.horsepower = horsepower  # 馬力の指定
        self.color = color  # 色の指定
        self.passengers = passengers  # 乗車人数の指定
        self.energy = energy
        print("馬力:%s" % (self.horsepower))
        print("色:%s" % (self.color))
        print("乗車人数:%s" % (self.passengers))
        print("動力源:%s" % (self.energy))

    def run(self):  # 走るメソッドの記載(メソッドも慣例的に第一引数に"self"を入れる)
        print("run function")

    def stop(self):  # 止まるメソッドの記載
        print("stop function")

    def turns(self):  # 曲がるメソッドの記載
        print("turns function")


class AutoDrive(Car):

    def stop(self):
        print("stop function with regenerative brake")

    def autodrive(self):  # 自動運転メソッド
        print("AI Drivemode")    


print("\ncar2")
car2 = Car(100, "green", 4, "ガソリン")  # 乗用車をインスタンス化
car2.run()
car2.stop()
car2.turns()
print("\ncar3")
car3 = AutoDrive(100, "green", 4, "電気")  # Carクラスを継承したAutoDriveクラスをインスタンス化
car3.run()
car3.stop()
car3.turns()
car3.autodrive()
先ほどまでのコードとの違いはAutoDriveメソッド内にstopメソッドを再定義していることです。このように記載することで、親クラス内で定義されたメソッドではなく、子クラス内で再定義されたメソッドの内容が呼び出されます。

このプログラムの実行結果は下記のとおりです。

上記図よりStop関数を呼び出した挙動が変わっていることが分かると思います。

superを使った継承

オーバーライドの場合だとメソッドの中身を全て上書きしてしまいます。ただ、場合によっては上書きではなく、親のメソッドの中身に子メソッド独自の内容を追加したい場合があると思います。そのような時にsuperを使って継承を行います。

これだと分からないと思うので、具体的にサンプルコードで見てみます。

superを使った継承のサンプルコード

superは下記のようにsuper().親クラスのメソッドで記述することが出来ます。
class AutoDrive(Car):
    def __init__(self, horsepower, color, passengers, energy, camera):
        super().__init__(horsepower, color, passengers, energy)
        self.camera = camera
        print("カメラの個数:%s" % (self.camera))
superを使う際の注意点ですが、クラス内では第一引数にselfを入れると記載しましたが、superの場合は例外で、第一引数にselfを入れないです。(詳細の説明は割愛しますが)

上記サンプルコードではカメラをコンストラクタ内で初期化し、printする処理を追加しました。上記コードを追加したものは以下の通りです。

# クラスの定義
class Car:  # 自動車の作るクラス

    def __init__(self, horsepower, color, passengers, energy):  # コンストラクタの記述(慣例的に第一引数は"self"とする)
        self.horsepower = horsepower  # 馬力の指定
        self.color = color  # 色の指定
        self.passengers = passengers  # 乗車人数の指定
        self.energy = energy
        print("馬力:%s" % (self.horsepower))
        print("色:%s" % (self.color))
        print("乗車人数:%s" % (self.passengers))
        print("動力源:%s" % (self.energy))

    def run(self):  # 走るメソッドの記載(メソッドも慣例的に第一引数に"self"を入れる)
        print("run function")

    def stop(self):  # 止まるメソッドの記載
        print("stop function")

    def turns(self):  # 曲がるメソッドの記載
        print("turns function")


class AutoDrive(Car):
    def __init__(self, horsepower, color, passengers, energy, camera):
        super().__init__(horsepower, color, passengers, energy)
        self.camera = camera
        print("カメラの個数:%s" % (self.camera))

    def stop(self):
        print("stop function with regenerative brake")

    def autodrive(self):  # 自動運転メソッド
        print("AI Drivemode")


print("\ncar2")
car2 = Car(100, "green", 4, "ガソリン")  # 乗用車をインスタンス化
car2.run()
car2.stop()
car2.turns()
print("\ncar3")
car3 = AutoDrive(100, "green", 4, "電気", 3)  # Carクラスを継承したAutoDriveクラスをインスタンス化
car3.run()
car3.stop()
car3.turns()
car3.autodrive()
このコードの実行結果は以下の通りです。

AutoDriveクラス内では馬力などの情報の代入処理は実施していませんが、メソッドが上書きされずにカメラの個数の代入処理が追加されていることが分かります。

まとめ

今回はクラスについて勉強しました。クラスとは設計図を作るようなイメージで、似たようなものを複数作りたい場合に便利です。また、継承やオーバーライドを使うことで機能の追加を効率よく行うことが出来ます。

クラスには他にもデコントラクタや多重継承などもあるのですが、記事が長くなりすぎてしまうので、この記事はここまでにしたいと思います。

参考文献






自己紹介

はじめまして 社会人になってからバイクやプログラミングなどを始めました。 プログラミングや整備の記事を書いていますが、独学なので間違った情報が多いかもしれません。 間違っている情報や改善点がありましたらコメントしていただけると幸いです。

X(旧Twitter)

フォローお願いします!

QooQ