基本情報ではじめる Python (5) オブジェクト指向


2021-09-21 更新

error

この記事は基本情報技術者試験の旧制度( 2022 年以前)の記事です。
この記事の題材となっている「午後問題」は現在の試験制度では出題されません。 ご注意くださいませ。

この連載では、プログラミングの入門者を対象として、基本情報技術者試験の出題範囲にテーマを絞って、 Python の言語構文とプログラムの読み方を説明します。

今回のテーマは、 Python によるオブジェクト指向の基礎です。オブジェクト指向は、情報処理推進機構が公開している Python のサンプル問題でも取り上げられている重要なテーマなので、しっかりとマスターしてください。

オブジェクト指向とは?

オブジェクト指向は、プログラムの部品化に関する指向です。 Python では、プログラムの部品化に 2 つの指向が使えます。プロセス指向オブジェクト指向です。

プロセス指向では、関数を部品にします。
オブジェクト指向では、クラスを部品にします。

どちらの指向を使うのかは、プログラマの好みの問題ですが、一般的に言うと、小規模なプログラムには、プロセス指向が適していて、大規模なプログラムには、オブジェクト指向が適しています。

 

関数は、単独の機能を持った小さな部品です。関数は、外部から引数として渡されたデータを使って処理を行います。
クラスは、複数の機能を持った大きな部品です。クラスは、内部に保持しているデータを使って処理を行います。

たとえば、半径の値から、円周の長さと円の面積を求める部品を作るとしましょう。

プロセス指向
外部から引数として渡された半径の値から円周の長さを求める circle_perimeter 関数と、面積を求める circle_area 関数を、別々に作ることになります
オブジェクト指向
内部に半径の値を保持し、その値を使って円周の長さを求める perimeter メソッド と、円の面積を求める area メソッドを持つ、 Circle クラスを作ることになります
メソッド( method = 「やり方」)とは、クラスが持つ処理のこと

以下は、オブジェクト指向の図示技法としてよく使われる UML ( Unified Modeling Language )のクラス図を使って、 Circle クラスを示したものです。

info編集部注: スマートフォンでご覧の際は、プログラムや表は横スクロールすると全文をご覧になれます

Circle fast_forwardクラス名
radius fast_forwardクラスが内部に保持するデータ
perimeter()
area()
fast_forwardクラスが持つメソッド

クラス図では、四角形を 3 段階に区切り、上段にクラス名(ここでは Circle )、中段にクラスが内部に保持するデータ(ここでは radius )、下段にクラスが持つメソッド(ここでは perimeter() と area() )を記述します。メソッドは、メソッドあることがわかりやすいように、メソッド名の後に () を付けます。オブジェクト指向では、個々のメソッドではなく、クラス全体が 1 つの部品です。

クラスを定義する方法

先ほど UML のクラス図で示した Circle クラスを、 Python のプログラムで表してみましょう。

以下は、 Circle クラスを定義です。このプログラムを Circle.py というファイル名で作成しましょう。

infoお手元に Python の環境がない場合、ブラウザからオンラインで実行できる「 JupyterLab 」で、文中のコードをお試しください。 play_arrow ボタンを押すか「 Shift + Enter 」で実行できます

codePython で Circle クラスを定義したプログラム ( Circle.py )
# Circleクラスの定義
class Circle:
    # 初期化メソッドの定義
    def __init__(self, radius):
        self.radius = radius

    # 円周の長さを求めるメソッド
    def perimeter(self):
        return self.radius * 2 * 3.14

    # 円の面積を求めるメソッド
    def area(self):
        return self.radius * self.radius * 3.14

クラスは、

class クラス名:

という構文で定義します。

クラスのブロックの中に

def メソッド名(self, その他の引数, ・・・)

という構文で、メソッドを定義します。

メソッドを定義する構文は、関数を定義する構文と同様ですが、第 1 引数を self にする約束になっています。この self は「自分」という意味であり、そのクラスのインスタンス(インスタンスについてはあとで説明します)の識別情報が自動的に格納されます。それによって、メソッドの処理の中では、

self.変数名

という構文で、クラスのインスタンスが持つデータを読み書きできます。このデータをインスタンス変数と呼びます。

perimeter メソッドは、

self.radius * 2 * 3.14

という計算で得られる円周の長さを返します。

area メソッドは、

self.radius * self.radius * 3.14

という計算で得られる円の面積を返します。

self.radius は、「自分が保持しているインスタンス変数 radius 」という意味です。それでは、インスタンス変数 radius の実体は、どこにあるのでしょう?

それは、 __init__ メソッドの処理内容を見ればわかります。

特殊メソッド __init__ の役割

先ほど UML のクラス図で示した Circle クラスには、ありませんでしたが、 Python でクラスを定義するときには、 __init__ メソッドを記述します。 init は、 initialize (初期化)という意味です。

メソッド名の前後に、アンダースコア( _ )が 2 つずつあるのは、特定の場面で自動的に呼び出される特殊メソッドであることを意味しています。 __init__ メソッドは、クラスのインスタンスが生成された直後に、自動的に呼び出される特殊メソッドです。

__init__ メソッドの処理として、何を行うのかは、プログラムの目的次第ですが、多くの場合に、インスタンス変数を作成します。

self.radius = radius

の部分で、インスタンス変数 radius を作成し、それに radius という値を設定しています。

左辺も右辺も radius なので、混乱するかもしれませんが、 self が付いている self.radius がインスタンス変数であり、 self が付いていない radius は外部から引数として __init__ メソッドに渡された半径の値です。 Python は、変数を宣言せずに使う言語なので、この self.radius = radius によって、インスタンス変数 radius が作成されます。

インスタンスを生成して使う方法

クラスは、オブジェクトを定義したものです。クラスは、その機能が必要になった時点で、メモリにロードして使います。メモリにロードされたクラスが オブジェクト であり、クラスの インスタンス( instance = 「実例」)とも呼ばれます。

クラスを定義したプログラムは、ハードディスク上にあります。このプログラムをメモリにロードしたものが、クラスのインスタンスです。 1 つのクラスから、複数のインスタンスを生成することもできます。生成とは、メモリにロードすることです。

たとえば、以下の例は、 Circle クラスのインスタンスを 2 つ生成して、それぞれに c1 および c2 という名前を付けたときの、ハードディスクとメモリのイメージです。

図 Circle クラスのインスタンスを 2 つ生成した例

Python のプログラムで、 Circle クラスのインスタンスを生成して使ってみましょう。

以下は、 Circle クラスのインスタンスを 2 つ生成して、それぞれの機能を使うプログラムを、 Python の対話モードで実行したところです。説明の都合で、行末にコメントを付けていますが、実際に実行するときには、コメントは不要です。

infoお手元に Python の環境がない場合、ブラウザからオンラインで実行できる「 JupyterLab 」で、文中のコードをお試しください。 play_arrow ボタンを押すか「 Shift + Enter 」で実行できます

code図 Circle クラスのインスタンスを生成して使う(対話モード)
>>> from Circle import Circle	# Circleをインポートする
>>> c1 = Circle(10)		# 半径 10 のインスタンス c1 を生成する
>>> c2 = Circle(100)	# 半径 100 のインスタンス c2 を生成する
>>> c1.perimeter()		# c1の円周を求める
62.800000000000004
>>> c2.perimeter()		# c2の円周を求める
628.0
>>> c1.area()			# c1の面積を求める
314.0
>>> c2.area()			# c2の面積を求める
31400.0

クラスのインスタンスは、 インスタンス名 = クラス名(引数) という構文で生成します。

c1 = Circle(10)

によって Circle クラスのインスタンス c1 が生成され、引数 radius に 10 という値が渡されて __init__ メソッドが自動的に呼び出されます。

クラスの定義では、メソッドの第 1 引数に self がありますが、メソッドを呼び出すときには、 self を指定しません。 self は、自動的に付加されるようになっているからです。

同様に、

c2 = Circle(100)

によって Circle クラスのインスタンス c2 が生成され、引数 radius に 100 という値が渡されて __init__ メソッドが自動的に呼び出されます。

 

それぞれの半径の値を内部に保持したインスタンス c1 と c2 が生成されました。これ以降では、 インスタンス名.メソッド名() という構文で、メソッドを呼び出して使います。

c1.perimeter() c1.area() で、 c1 の円周と面積が求められます。
c2.perimeter() c2.area() で、 c2 の円周と面積が求められます。

perimeter メソッドと area メソッドを呼び出すときに、引数に半径の値を指定していないことに注目してください。これは、どちらのメソッドも、内部に保持している半径の値を使って処理を行っているからです。

いかがでしたか。 Python によるオブジェクト指向の基礎を、しっかりとマスターできたでしょう。

この連載では、今後も、基本情報技術者試験を Python で受けるための知識を取り上げて行きます。

それでは、またお会いしましょう!

 

label 関連タグ
科目A試験は、
免除できます。
独習ゼミで科目A試験を1年間免除して、科目B試験だけに集中しましょう。
免除試験を受けた 74.9% の方が、
科目A免除資格を得ています。
科目A免除試験 最大 2 回の
受験チャンス !
info_outline
科目A免除試験 最大 2 回の
受験チャンス !
詳しく見てみるplay_circle_filled
label これまでの『基本情報ではじめるPython』の連載一覧 label 著者