オブジェクト指向プログラミング


 

 

オブジェクト指向プログラミング

 プログラミング言語は、その設計思想によって大きく2種類のタイプに分けられます。1つは関数型言語とよばれるものであり、Haskell や Scala などがその代表例です。もう1つは Java や Ruby, PHP などに代表されるオブジェクト指向言語です。

 Python はオブジェクト指向言語に分類されます。実際には関数型も巧みに組合わせて処理するので「関数型 + オブジェクト指向言語」と呼んだほうが正確かもしれませんが、極めてオブジェクト指向の強い言語であることは確かです。

 object は英語で「物、物品、物体」という抽象的な意味をもつ単語です。テーブル、机、書棚、パソコン、ボール、シャープペン ...... これらはすべて「モノ」の範疇に含まれますが、その機能や用途はそれぞれ異なっています。たとえばテレビには「電波を受信して画面に表示する」、「チャンネルを変える」、「見たい番組を検索する」といった機能があり、エアコンには「室温を設定する」、「除湿する」、「風向を変える」という機能が備わっています。テレビとエアコンでは、当然見た目や寸法も違います。
 このように「モノ」の種類によって形態や機能が異なっていることは日常生活の中でもごく自然な感覚であり、オブジェクト指向とは、そうした「モノ」の概念をプログラミングの世界に持ち込んで設計されたシステムなのです。

 プログラミング言語で「モノ」に相当するのは、「データとデータのもつ性質」です。Python ではデータとクラス変数、インスタンス変数、メソッドが「モノ」、すなわちオブジェクトであると定義されています。クラス変数やインスタンス変数はオブジェクトの見た目や形態を決定します。メソッドはオブジェクトのもつ固有の機能です。たとえば "apple" という文字列は「自身と他の文字列を連結させた別の文字列を生成する」という join()メソッドを備えています。

 "apple" と "orange" は異なるオブジェクトですが、どちらも strクラス(文字列型)に属します。同様に数値の 1 と 2 は intクラス(整数型)に、1.0 と 2.0 は floatクラス(浮動小数点数型)に属しています(あるオブジェクトがどのクラスに分類されるのかは、type関数を用いて簡単に調べることができるので色々と試してみてください)。同じクラスのオブジェクトは見た目(インスタンス変数やクラス変数)は個々で微妙に異なっていても同じ機能を備えています。
 strクラスのオブジェクトであれば連結機能を備えているし、intクラスや floatクラスのオブジェクトは互いに加えたり引いたりする演算機能を備えています。
 詳細については個々の記事で解説しますが、クラスとはオブジェクトの設計図です。この設計図に書かれた仕様にしたがって個々のオブジェクトが生み出されています。int や float, str などは組み込みのクラスですが、モジュールをインポートすることで、組み込み以外のクラスのオブジェクトを作り出すことができるようになります。また、ユーザー自身が新しいクラスを定義することも可能です。最初のうちはクラスとオブジェクトの概念を把握することは難しいかもしれません。しかし実際にコードの中でクラスを定義する経験を繰り返すことによって、その構造を自然と理解できるようになります。

クラスとオブジェクト

 Pythonでは、あらゆるものが オブジェクト です。整数 100 はオブジェクトであり、文字列 "Python" や真偽値の True や False もオブジェクトです。すべてのオブジェクトは何かの クラス に属しています。Type()関数を使うと、あるオブジェクトがどのクラスに分類されているかを調べることができます。

# CLASS_01-1

# 100のクラス
print(type(100))

# "Python" のクラス
print(type("Python"))

# Trueのクラス
print(type(True))
<class 'int'>
<class 'str'>
<class 'bool'>

 サンプルコードを実行すると、100 は intクラス、"Python" は strクラス、True は boolクラスに属していることがわかります。
 

インスタンス

 クラスはオブジェクトの性質を定義するものです。オブジェクトがプログラミングに欠かせない部品であるとすれば、クラスは部品の設計図です。設計図(クラス)から部品(オブジェクト)を製造することをクラスの インスタンス化 と表現します。

 すべてのオブジェクトは、必ずあるクラスのインスタンスとして生成されます。intクラスから 100 や 200 というインスタンスが作られ、strクラスから "apple" や "orange" というインスタンスが作られます。インスタンスオブジェクト は同じ意味ですが、「あるクラスから作られたオブジェクト」であることを強調したいときに、インスタンスという言葉を使います。

 Pythonには、intクラスや floatクラス, strクラスなど、あらかじめ用意されている組み込みクラスがあります。これらのクラスから生成するインスタンス(オブジェクト)は頻繁に活用するので、特別な手続きなしで使えるようになっています。

 モジュールをインポートすると、組み込み以外のクラスを使うことができるようになります。たとえば、fractionsモジュールをインポートすると、Fraction というクラスが追加されます。Fractionクラスからは分数(有理数)というインスタンスを作ることができます。
 

クラスの定義

 クラスは自分で定義することもできます。
 新しいクラスを定義するときは、

 class クラス名:
   スイート

という形式で記述します。一般的にクラス名は関数やメソッド、あるいは組み込みのクラスと区別するために、クラス名の先頭は大文字にするという慣例があります。クラス名のあとに改行し、半角 4 文字でインデントして、スイートとよばれるにメソッドやクラス変数、インスタンス変数などを記述します。

 以下のサンプルコードでは「長方形の性質をもつオブジェクト」を生み出すための Rectangles クラスを定義しています。

# CLASS_02-1

# Rectanglesクラスの定義
class Rectangles:
    def __init__(self, a, b):
        self.width = a
        self.length = b
    
    def area(self):
        return self.width * self.length

 Rectangles がクラス名です。続く行に def 文を使ってクラス内部に関数が定義されています。これがメソッドの正体です。

 __init__() はクラスのインスタンスが生成されるときに自動的に実行されるメソッドです。Rectangles クラスはオブジェクト自身がもつ変数 (インスタンス変数) width と length に数値 a, b を代入するようになっています。これはインスタンスを生成するときにユーザーが引数として渡す値です。実際に1つのオブジェクトを生成してみましょう。コンストラクタは Rectangles(a, b) です。

# CLASS_02-2

# Rectanglesクラスのインスタンスを生成
rec = Rectangles(10, 20)

 これで、インスタンス変数 width と length にそれぞれ 10, 20 という値をもつ Rectangles オブジェクトが生成されました。格納された値は属性値として参照できます:

# CLASS_02-3

# 長方形の二辺の長さを取得
print(rec.width)
print(rec.length)
10
20

 インスタンス生成時に、引数に様々な値が渡すことができるので、個々のオブジェクトのもつ属性値は互いに異なっています。縦横の長さが (10, 20) の長方形もあれば、(15, 30) や (50, 80) の長方形もあります。(50, 50) という正方形も長方形の一種です。確かにどれも少しずつ異なっているのですが、「二辺の長さをもつ」という長方形の性質は維持されています。

 この例からわかるように、クラスはオブジェクトの大まかな特徴を設計しますが、細部については実際にオブジェクトが生成された時点で確定するようになっています。

 Python Rectangles(長方形)クラスのインスタンス

 def __init__() には、a, b の前に self という引数が定義されていますね。クラスメソッドの第 1 引数には必ず self を指定するという決まりがあります。インスタンスが生成されると、self にインスタンス自身が渡されて、self.[変数] という形式でインスタンス変数が値を受け取れる仕組みになっています。

 慣れないうちは理解しにくいかもしれませんが、あまり深く考えずに「こう書く決まりになっているのだ」ぐらいに覚えるようにしてください。プログラミングに慣れてくると (不思議なことに) こうした仕組みを自然と理解できるようになります。

 Rectangles クラスには、もうひとつ、area() というメソッドが定義されています。area()メソッドは内部で self.width と self.length を掛け合わせて長方形の面積を計算します。先ほど作成したオブジェクトの面積を取得してみましょう。

# CLASS_02-4

print(rec.area())
200

 次回記事では、クラス変数とインスタンス変数について詳しく学びます。