【初心者向け】クラスとは何か?

はじめに

Pythonはオブジェクト指向言語と呼ばれております。
この章ではこのオブジェクト指向言語の理解には欠かせない、『クラス』の基本に関して説明します。
Pythonに限らず、オブジェクト指向言語には、クラスを使うことが出来ます。
オブジェクト指向は理解がしにくいものですので、
このテキストだけで全てを理解しようとせず、こういうものなんだなという程度の理解で構いませんので、自分のペースで学習を続けてください。

重要な用語

今回この章の中では、以下の10つの重要な用語が登場します。
これらは、Pythonに限らずオブジェクト指向言語(Javaなど)には全て持ち合わせています。
用語の意味がわからなくなったら、1つ1つそれを説明しているセクションに戻り、復習をしてみてください。

1.オブジェクト指向
2.クラス
3.オブジェクト
4.コンストラクタ
5.インスタンス
6.メソッド
7.継承
8.多重継承
9.オーバーライド
10.親クラスと子クラス

オブジェクト指向

オブジェクト指向とはプログラミングのスタイル・手法のことで、プログラミングパラダイムと呼ばれる1つです。
プログラミングパラダイムには、オブジェクト指向(オブジェクト指向プログラミング)以外にも、関数型プログラミング、手続き型プログラミングがあります。
手続き型プログラミングでは、連続した手続きを記述し、上から下へと流れ、変数などの状態が変化しながらコードを書いていきます。
例えば、手続き型とは次のようなものを言います。

a = 10
b = 20
y = a + b
print(y) # 20

しかし、手続き型プログラミングには、すべてのコードがグローバル変数なため、プログラムが多くなるにつれ様々な問題が出てきます。
例えば、ある関数でグローバル変数を変更し、別で書いた関数でそのグローバル変数を上書きするなどです。
こうすると手続き型プログラミングの場合、次第にプログラムを管理することが困難になってきます。
その問題を解決するきっかけにオブジェクト指向プログラミングが登場しています。
オブジェクト指向は上記の問題を解決するだけでなく、開発の効率や保守性を上げることが出来ます。
オブジェクト指向を活用可能なプログラミング言語は、PythonやJava、C++といった言語が挙げられます。
今回は、Pythonを使いオブジェクト指向の基礎となるクラスから説明していきます。

クラス

以前、intやstrなどのデータ型を見てきましたが、クラスとはデータ構造を作る仕組みで、クラスを使うと新しいデータ型を作ることができます。
よくクラスは、オブジェクトを作る設計書と説明されます。
クラスとインスタンスの関係のイメージ図です。

クラス(データ構造を作る仕組みで設計図)→インスタンス化(たこ焼きを焼く)によりインスタンス(オブジェクト)を作成します。

インスタンス化というのはクラスからインスタンス(オブジェクト)を作ることです。
オブジェクトに関して次のセクションにて説明致します。

では早速実際にクラスを作ってみましょう。

"""
クラスを作る時は、CamelCase(キャメルケース)「単語の頭文字を大文字にして接続する書式」で作るようにしてください。
また、関数やこの章で登場するメソッドの場合は、スネークケース(小文字の単語同士をアンダースコアで繋ぐ形式)を使います。(余談ですが、小文字のみでアンダースコアなしのことをlowerケースと呼びます。)
"""

# Sampleクラスを作ります。(保存するファイル名は任意の名前で可能です。)
class SampleClass: # クラス名の最初の文字は大文字で、また複数の単語の頭文字は大文字にします
    # クラス内ではスペースを4つ開けてインデントしてください。クラスの中には変数やメソッド(クラスの中にある関数をメソッド)を定義できます。
     '''sample class '''

sample = SampleClass() # インスタンス クラスを使うには、関数の呼び出しのように、クラス名()することでインスタンス化します。こうすることでクラスを使うことができます。sampleにSampleClassのインスタンスが格納されました。クラスからつくられたこのデータをインスタンスと呼びます。

sample.name = "A"
sample2 = SampleClass() # このSample型から、いくつでもデータを作ることができるのでsample2を作りましょう。

sample2.name = "B" # sample2に対してさまざなな属性を作ることができる。

print(sample.name) # sampleの名前はA
print(sample2.name) # sample2の名前はB

空のクラス(中身のないクラス)を作るには次のように書きます。

class SampleClass:
    pass # passを使うことで空のクラス(や関数)を作ることが出来ます。

sample = SampleClass()
sample.name = "Sample"

オブジェクト

オブジェクトとはデータ(属性)とメソッド(クラスに定義された関数)を持ったものです。
そして、Pythonの値は全てオブジェクトであり、オブジェクトには実行で出来る関数(メソッド)が定義されています。

初期化メソッド

初期化メソッドは対象のクラスのインスタンスを初期化するために利用します。
メソッドとは、後述しますが、クラスに定義された関数のことです。
インスタンスを作る時に初期値を与えたい時に初期化メソッドを使うと便利です。

※Pythonでは、初期化メソッドをコンストラクタと呼ぶ場合がありますが、厳密にはコンストラクタではなく、コンストラクタから呼び出される初期化メソッドになります。

クラスには__init__という特殊なメソッドを書くことができます。
これが初期化を行うメソッドでコンストラクタと呼び、クラスのインスタンスが作成される際に一度だけ呼ばれるメソッドです。
また、クラスが内包するデータを属性と呼びます。

実際に、プログラムを見ていきましょう。
(今回はUserクラスを作っていきます。)

class User:
    def __init__(self, name): # インスタンス化されて渡ってくる値を受ける変数を定義します
        # インスタンス変数(属性の初期化)
        self.name = name
        print("コンストラクタが呼ばれました")

    def hello(self):
        print("Hello " + self.name)

user = User("Sample User") # userというインスタンスを生成しています。

Userクラスのコンストラクタはnameという引数を取り、その引数で変数であるself.name(この変数のことをインスタンス変数と呼びます)を初期化しています。
インスタンス変数は、個々のインスタンスに格納される変数のことです。
ここではnameがインスタンス変数です。
helloメソッド内で、selfの後に属性名を書いていますが、このように書くことで、インスタンス変数の作成及びアクセスができます。

user = User("Sample User")
py = User("python")

user.hello()
py.hello()

メソッド

メソッドとはクラスに定義された関数のことです。
前回、空のSampleClassを定義しましたが、今回はメソッドを持つ、SampleClassを作ります。

class SampleClass:
    # メソッド メソッドには1つ目の引数selfを必ずつけてください。selfというのはクラスのインスタンス自身を指しています
    def set_name(self, name):
        self.name = name # 受け取った値をSampleClasasのインスタンスに格納する必要があります。そのためにself.name = nameとします。self自体がSampleClassのインスタンスをさしますので、nameと言うインスタンス変数を用意して引数nameを代入します。

    def hello(self):
        print("hello, {0}".format(self.name))


sample = SampleClass()
sample2 = SampleClass()
sample.set_name("Python") # selfは自分自身を示すものなので、nameに当たるPythonだけの引数だけで問題ありません。
sample2.set_name("AI")
sample.hello()
sample2.hello()

継承

継承は既存のクラスをもとに新しいクラスを作る仕組みです。
継承を利用することで既存のクラスの拡張が効率良く行なうことが可能になり、またプログラムの保守性も上がります。
User(親クラス・スーパークラス・基底クラス)-> SuperUser(子クラス・サブクラス・派生クラス)
これから定義する子クラスSuperUserクラスは、親クラスの機能が備わっているため、子クラスを定義する際には新しく追加したい機能だけを定義するだけで済みます。
継承することで既存のクラスを再利用し、新たなクラスを作成することができます。
では実際に見ていきましょう。

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

    def hello(self):
        print("Hello " + self.name)

class SuperUser(User): # ユーザークラスを継承するには、()の中にUserクラスを書けばoKです。
    def __init__(self, name, age):
        # super()を使うことで親クラスのメソッドを呼び出すことができます。
        super().__init__(name) # こクラスから親クラスのコンストラクタを呼び出す
        self.age = age

    # メソッドのオーバーライド
    def hello(self):
        print("SuperHello" + self.name)
        """
        またこクラスのメソッドの中で、例えばオーバライドした
        メソッド内で、super()を使うことで親クラスUserのメソッドを呼び出すこともできます。
        """
        super().hello()

t = SuperUser("tani", 100)
t.hello()

多重継承

多重継承とは、複数の親クラスから継承することです。
下記の例では、Base1とBase2の2つが親クラス(基底クラス)でその2つから継承されていることを意味します。

"""
Pythonは多重継承をサポートしています。
複数の基底クラスを持つクラス定義は次のような構文になります。
"""
class SampleClassName(Base1, Base2):
    ・・・・
    ・・・・
    # 上記のBase1を継承した後にBase2を継承します。

メソッドのオーバライド

メソッドを独自の機能で上書きすることをオーバーライド(over ride)と言います。
下記のDerivedクラス内のsampleメソッドがBaseクラスのsampleメソッドをオーバーライドすることで上書きされています。
今回sampleメソッドのみオーバーライドしましたが、__init()__を含むあらゆるメソッドをオーバーライド出来ます。

# 基底クラス
class Base:
    def sample(self):
        print("Base.sample()が呼ばれました")

    def test(self):
        print("Baseクラスtestメソッドが呼ばれました")

# 派生クラス
class Derived(Base):
    def sample(self): # Baseクラスのsampleメソッドをオーバーライド
        print("Derived.sample()が呼ばれました")
        self.test() # Baseクラスのtestメソッドを呼び出し

d = Derived()
d.sample()

元のBaseクラスは、親クラスもしくはスーパークラス(もしくは基底クラス)と呼ばれます。
新しくできたDerivedクラスは子クラス、サブクラス、派生クラスなどと呼ばれます。

まとめ

この章ではクラスとオブジェクトに関して見てきました。
最初のうちはクラスを使う必要性はあまり感じられないかもしれません。
ですが、大規模なアプリケーション開発をする場合にはクラスを使うことが多くなってきます。
興味を持った方は、「オブジェクト指向」に関して調べてみてください。

演習問題

  1. 生徒のテストの点数を管理するクラスを作ってください。
    コンストラクタには、scoreという変数をクラス内に定義し、scoreは辞書型で管理してください。
    例) {“english”: 99, “math”: 49}
  2. 会員情報を保持するUserクラスを以下の指示にしたがって作成してください
    クラス名: User
    属性(コンストラクタで定義する、クラスが内包するデータのこと):
    会員ID(user_id)
    ユーザーネーム(username)
    メールアドレス(email)
  3. 2で作成したクラスに、get_userinfo()というメソッドを追記して呼び出してください。
    このメソッドを呼び出したら、usernameとemailを出力してください。

演習問題解答例

Leave a Reply