Python入門【クラスの使い方とオブジェクト指向】

Python クラス

こんにちは、ミナトです。

「クラスって何?クラスってどのように使うの?」

などと疑問に思われていないでしょうか?

今回はプログラミング初心者の方のために、オブジェクト指向とPythonでのクラスの使い方について分かりやすく解説します。

今回はオブジェクト指向とクラスの使い方について解説するで😆
初心者にも分かりやすいように一から解説するから安心してな!
以下のような方を対象としています
  • オブジェクト指向とは何か知りたい
  • Pythonでのクラスの使い方を知りたい
  • Pythonでプログラミングを学びたい

クラスとオブジェクト指向

オブジェクト指向とは

オブジェクト指向プログラミングとは、プログラムを「モノ(オブジェクト)」として考え、「モノ」を組み立て、操作するように開発する手法のことです。

オブジェクトはデータと処理の集まりであり、車オブジェクトや人オブジェクトのようなモノを作成して組み合わせることでプログラミングを行っていきます。

オブジェクト指向で開発するメリットは以下の通りです。

オブジェクト指向のメリット
  • 分業化しやすい
  • 機能の拡張や修正がしやすい
  • 品質が向上する

オブジェクトとクラス

オブジェクトは「物体」「物」という意味で、プログラミングでは、データと処理の集まりとなります。

オブジェクト指向の重要な要素としてクラスがあります。クラスとは、プログラムの中でオブジェクトを作成するための設計書のようなものです。

クラスには、プロパティ(データ)メソッド(処理)を定義します。

クラスは設計書なので、プログラムの中で実際に利用する際はインスタンスという実態を作成して利用することになります。

説明だけだと分かりにくいと思いますので、以降は実際にPythonでクラスを定義して利用する方法を解説します。

クラスの定義

クラスの定義

class クラス名:
 クラスの内容

以下の例では、何もしないCarクラスを定義しています。passは何も処理をしないことを意味しています。

class Car:
    pass

クラスの初期化

続いてクラスの初期化を行います。(インスタンスの作成)

クラスの初期化は関数の呼び出しのようにクラス名に「()」をつけます。

クラスの初期化

クラス名()

car1 = Car()

クラスを一度定義しておくと、設計書から複数のインスタンスを何個でも作成できます。

car1 = Car()
car2 = Car()
car3 = Car()

クラス変数

クラスには、以下のようにクラス変数を定義できます。
クラス変数はクラス間で共通で、複数インスタンスを作成しても同じ値になります。

クラス変数は以下のように定義します。

クラス変数の定義

class クラス名:
 クラス変数名 = 値

クラス変数へのアクセス

クラス名.クラス変数名

以下の例では、makerというクラス変数を定義しており、Car.maker = 'TOYOTA'でクラス変数の値を変更しています。

クラス変数は全てのCarクラスのインスタンスで共有されるので、全てのインスタンスで値が変わっていることを確認しています。

class Car:
    maker = 'Mercedes-Benz'


car1 = Car()
car2 = Car()
car3 = Car()

print(car1.maker)
print(car2.maker)
print(car3.maker)

Car.maker = 'TOYOTA'

print(car1.maker)
print(car2.maker)
print(car3.maker)


## 出力
Mercedes-Benz
Mercedes-Benz
Mercedes-Benz
TOYOTA
TOYOTA
TOYOTA

コンストラクタ

インスタンスが作成される時に呼ばれる処理をコンストラクタと呼びます。

Pythonではコンストラクタを以下のように定義します。

コンストラクタの定義

class クラス名:
 def __init__(self, 引数1, 引数2 …):

selfはインスタンス自身という意味を表しています。

self.name = name と記述している箇所はインスタンス変数といい、先程のクラス変数と異なり、インスタンスごとに値を保持します。

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


car1 = Car('C-class')
car2 = Car('E-class')
car3 = Car('S-class')

print(car1.name)
print(car2.name)
print(car3.name)

## 出力
C-class
E-class
S-class

デストラクタ

インスタンスが削除される時に実行される処理をデストラクタと呼びます。

Pythonではデストラクタを以下のように定義します。

デストラクタの定義

class クラス名:
 def __del__(self):

以下の例では、del文でcar1を削除し、デストラクタが実行されることを確認しています。

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

    def __del__(self):
        print('削除されます。')


car1 = Car('C-class')
del car1

## 出力
削除されます。

メソッドの定義

メソッドはクラスの持つ処理のことです。

上では、__init__()と__del__という特殊なメソッドを定義してましたが、任意の名前のメソッドを定義することも可能です。

メソッドの定義は以下のように記述します。基本的に関数の定義とほとんど同じです。

メソッドを実行する際は「インスタンス名.メソッド名()」として実行します。

メソッドの定義

class クラス名:
 def メソッド名(self, 引数1, 引数2 …):

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

    def drive(self, speed):
        print(f'{self.name}が{speed}km/時で走行します。')


car1 = Car('C-class')
car1.drive(60)

## 出力
C-classが60km/時で走行します。

カプセル化

オブジェクト指向の重要な考え方にカプセル化というものがあります。

カプセル化はクラスの外部から変数に自由にアクセスできないようにする方法です。

通常Pythonの変数やメソッドには外部から自由にアクセスできてしまいます。外部から変数を自由に書き変えられると思わぬ不具合につながるケースがあります。

そこで、カプセル化を利用して、クラスの外部から変数にアクセスできなくします。

「それではどのように変数にアクセスするの?」と思われるかと思います。

そこで、gettersetterを利用します。getterは読み取り専用のメソッドでPythonではプロパティとも呼ばれます。また、setterは書き込み専用のメソッドとなります。メソッドの形式で定義しますが、アクセスする際に「()」は不要です。

プロパティ(setter)

まずはプロパティの使い方をみていきましょう。

プロパティの定義は以下のように変数にアンダースコア(_)を付けて定義します。さらに@propertyを付けたメソッドを定義します。

こうすることで読み取り専用のプロパティが定義できます。

プロパティの定義

class クラス名:
 def __init__(self, 引数):
  self._変数名 = 引数

 @property
 def プロパティ名(self):
  return self._変数名

以下の例では、nameプロパティを定義してアクセスしています。
car1.nameで値のアクセスはできますが、car1.name = 'XX-class'で値の代入をしようとするとエラーとなります。

class Car:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name


car1 = Car('C-class')
print(car1.name)
car1.name = 'XX-class'

## 出力
C-class
Traceback (most recent call last):
  File "/Users/minato/PycharmProjects/pythonProject/lesson1.py", line 16, in <module>
    car1.name = 'XX-class'
AttributeError: can't set attribute

しかし、実際は元の_name変数の名前を知っていれば、以下のように変数にアクセスできてしまいます。

car1 = Car('C-class')
print(car1.name)
car1._name = 'XX-class'
print(car1.name)

## 出力
C-class
XX-class

そこでより厳しく制限するためにはアンダースコアを2つ付けます。
こうしておくとクラスの外から__nameにアクセスできなくなります。(読み取りも書き込みも不可)

class Car:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

car1 = Car('C-class')
print(car1.__name)

## 出力
AttributeError: 'Car' object has no attribute '__name'

上記の例でクラスの外からアクセスできないことが確認できました。ただし、同じクラスの内部からはアクセス可能です。

class Car:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    def drive(self, speed):
        print(f'{self.__name}が{speed}km/時で走行します。')


car1 = Car('C-class')
car1.drive(100)

## 出力
C-classが100km/時で走行します。

getter

上記まででプロパティの使い方を紹介しました。しかし、「どのように変数を書き換えるの」と思われるかと思います。そこで利用するのがsetterです。

setterは以下のように記述します。

setterの定義

class クラス名:
 def __init__(self, 引数):
  self.__変数名 = 引数

 @property
 def プロパティ名(self):
  return self._変数名

 @プロパティ名.setter
 def setter名(self, 引数):
  self.__変数名 = 引数

以下の例では、setterを定義して、car1.name = 'XX-class'で変数を上書きしています。

class Car:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name


car1 = Car('C-class')
print(car1.name)
car1.name = 'XX-class'
print(car1.name)

## 出力
C-class
XX-class

setterの使いどころとしては、ある条件が合致した場合のみ値を書き換え可能とするというようなケースが考えられます。

話が複雑になってしまったので、簡単にまとめると以下となります。

カプセル化のまとめ
  • インスタンス変数に_(アンダースコア1つ)をつける・・・プログラマにこの変数にクラスの外部からアクセスするにはgetter・setterを使ってと伝える。しかし実際はクラスの外部からアクセスできる。
  • インスタンス変数に__(アンダースコア2つ)をつける・・・クラスの外部からアクセスできなくなる。参照するにはプロパティ(getter)を利用する。
  • getter(プロパティ)・・・隠蔽された変数の値を取得する時に利用する。
  • setter・・・隠蔽された変数に値をセットする時に使う。

まとめ

今回はオブジェクト指向とPythonでのクラスの使い方について解説しました。

最後に復習として、今回の内容を簡単に整理して起きます。

setterの定義
  • オブジェクト指向プログラミングとは、プログラムを「モノ(オブジェクト)」として考え、「モノ」を組み立て、操作するように開発する手法のこと
  • クラスはオブジェクトの設計書のようなもので、データと処理をひとまとめにして管理できる
  • クラスにはクラス変数インスタンス変数がある
  • クラスの処理はメソッドで定義する
  • コンストラクタ・デストラクタで、初期化処理と削除時の処理が定義できる
  • setter・getterを利用することでクラスの外部から変数に自由にアクセスできないように隠蔽できる。(カプセル化

実際のアプリケーション開発では、多くの場合クラスを利用するので、使い方を覚えておいてください。

次回はより応用的な内容としてクラスの継承などを扱いたいと思います。興味のある方はぜひご確認ください。

最後まで読んでいただき、ありがとうございます。

この記事が、「面白いな」、「勉強になったな」という方は、SNSでシェアしていただけると嬉しいです。