↓ メインコンテンツへスキップ
  1. 第06講 クラス(1/2)/

クラス定義

クラスとは
#

教科書 p.212(Lesson 8)

プログラムが複雑になってくると、関数とそれに関するデータをまとめて扱いたくなります。 そのために、Python では クラス(Class) という概念が用意されています。 クラスは、関数とデータをまとめたもので、オブジェクト指向プログラミング(OOP; Object-Oriented Programming)の基本的な概念です。

なお、クラスは内部に関数や変数を含む大きな変数の定義に相当し、利用するには実体化(インスタンス化; instantiation)が必要です。 この作成された実体(インスタンス; instance)のことを オブジェクト(Object) と呼びます。

クラスを定義する
#

クラスには、変数、関数を含められます。 クラスを定義するには、class キーワードを使います。 クラスの中身はインデントし、変数と関数を定義していきます。

クラスに含まれる関数は、最初の引数が self になっています。 self は、そのクラスのインスタンスを指します。 このような関数(クラスに含まれる関数のこと)を メソッド(Method) と呼びます。

また、クラスで定義される変数は、self.変数名 として利用できます。 このような変数のことを インスタンス変数(instance variable) と呼びます。

クラス内のメソッドとインスタンス変数は、クラスのインスタンス(オブジェクト)を通じてアクセスできます。 また、両者の名前の重複は許されず、あとから代入されたものが優先されます。

クラス利用の例
#

class Person:
    def get_name(self):  # get_name は Person クラスのメソッド
        return self.name # name は Person クラスのインスタンスに紐づいた変数
    
    def get_age(self):   # get_age は Person クラスのメソッド
        return self.age  # age も name と同じく、Person クラスのインスタンスに紐づいた変数
    
p = Person()        # Person クラスをインスタンス化して(Personオブジェクトを作成して)
                    # p に Person クラスのインスタンス(Person オブジェクト)を代入する。
p.name = "John Doe" # Person オブジェクト p の変数 name に "John Doe" を代入する。
p.age = 30          # Person オブジェクト p の変数 age に 30 を代入する。

print(f"{p.get_name()} is {p.get_age()} years old.")

実行結果
#

$ python3 person.py
John Doe is 30 years old.
  • このプログラムでは、Person クラスを定義し、get_name メソッドと get_age メソッドを定義しています。
  • 続いて、Person クラスをインスタンス化して p に Person クラスのインスタンス(Personオブジェクト)を代入します。
  • そして、Personオブジェクトである p の変数 name と age にそれぞれ "John Doe" と 30 を代入しています。
  • 最後に、Person クラスで定義されている get_name メソッドと get_age メソッドを呼び出して結果を出力しています。
    • get_name メソッド、get_age それぞれのメソッドの中で self.name と self.age として、Person のインスタンス変数 name と age にアクセスしています。

ドット記法
#

クラス利用の例でも見たように、インスタンス変数やメソッドにアクセスする際には、ドットを利用します。 このようなアクセス方法を ドット記法 と呼びます。

インスタンス名.インスタンス変数名
インスタンス名.メソッド名(引数リスト)

複数のインスタンス(Multiple Instances)
#

クラスを複数回インスタンス化することで、複数のオブジェクトを作成できます。 それぞれのオブジェクトは互いに影響せず、独立して動作します。

class Person:
    def get_name(self):
        return self.name
    
    def get_age(self):
        return self.age

    def print(self): # 自分自身の情報を出力するメソッド(関数ではない)
        print(f"{self.get_name()} is {self.get_age()} years old.")

def print_person(p): # Person を受け取り、その情報を出力する関数(メソッドではない)
    print(f"{p.get_name()} is {p.get_age()} years old.")

p1 = Person()        # 1つ目の Person オブジェクトを作成する。
p1.name = "John Doe" # p1 の name に "John Doe" を代入する。
p1.age = 30

p2 = Person()        # 2つ目の Person オブジェクトを作成する。
p2.name = "Jane Doe" # p2 の name に "Jane Doe" を代入する。
p2.age = 35

# p1 の print メソッドを用いて、p1 の情報を出力する。
p1.print() # => John Doe is 30 years old.
# p2 の print メソッドを用いて、p2 の情報を出力する。
p2.print() # => Jane Doe is 35 years old.

# print_person 関数を呼び出し、p1 の情報を出力する。
print_person(p1) # => John Doe is 30 years old.
# print_person 関数を呼び出し、p2 の情報を出力する。
print_person(p2) # => Jane Doe is 35 years old.

p1、p2はともに Person オブジェクトですが、それぞれ別の name、age という変数を持っています。 同様に、get_name、get_age、print メソッドもそれぞれのオブジェクトに紐づいています。 そのため、どのオブジェクトに対して、メソッドを呼び出したかによって、結果が異なります。

やってみよう: メソッドを追加する
#

person2.py を person4.py という名前でコピーし、Person クラスに次の 2 つのメソッドを自分で追加してください。

  • is_adult: 年齢が 18 歳以上なら True、そうでなければ False を返す。
  • greet: "Hello, I am John Doe." のような挨拶の文字列を返す(表示するのではなく、返す)。

追加できたら、3 つ目のオブジェクト p3(名前 "Taro Yamada"、年齢 15)を作り、p1、p2、p3 のそれぞれについて greet の返り値と is_adult の結果を表示してください。 実行結果は次のようになります。

Hello, I am John Doe. True
Hello, I am Jane Doe. True
Hello, I am Taro Yamada. False

p1.greet() と p3.greet() は同じメソッドを呼び出しているのに結果が違います。 self がそれぞれ別のオブジェクトを指しているからです。

🏁 解答例
class Person:
    def get_name(self):
        return self.name

    def get_age(self):
        return self.age

    def print(self):
        print(f"{self.get_name()} is {self.get_age()} years old.")

    def is_adult(self):            # 追加: 18 歳以上なら True。
        return self.age >= 18

    def greet(self):               # 追加: 挨拶の文字列を返す(表示はしない)。
        return f"Hello, I am {self.name}."

p1 = Person()
p1.name = "John Doe"
p1.age = 30

p2 = Person()
p2.name = "Jane Doe"
p2.age = 35

p3 = Person()
p3.name = "Taro Yamada"
p3.age = 15

print(p1.greet(), p1.is_adult())
print(p2.greet(), p2.is_adult())
print(p3.greet(), p3.is_adult())

self
#

selfは習慣的に、そのクラスのインスタンスを指す変数の名前として使われます。 習慣的に、ですので、別の名前でも構いません。 ただし、self 以外の名前を使うと、他のプログラマが混乱する可能性があるため、self を使うことが推奨されます。

class Person:
    def get_name(s):  # self という名前でなくても良い。
        return s.name # この場合、s という名前でインスタンス変数を利用する。
        # return name # s という名前を省略すると、単なるローカル変数として扱われる。
        #             # そのような変数はないので、エラーになる。
    
    def get_age(self):
        return self.age
    
p = Person()
p.name = "John Doe"
p.age = 30

print(f"{p.get_name()} is {p.get_age()} years old.")

参考
#