オブジェクト指向とクラス¶
現代のプログラミングの設計方法論として、最もメジャーなものがオブジェクト指向(Object-Oriented)です。オブジェクト指向においては、**クラス(Class)**という概念を用いて、それを設計の最小単位にします。変数だけを定義するとか、関数だけを定義することを許容せずに、必ず「クラスXXの変数」「クラスYYの関数」という形で、持ち主を明記するようにしています。
オブジェクト指向は、クラスを基準としたプログラムを設計する方法論の1つであると捉えてください。今はそれだけで充分です。
それ以上の解釈をすると「ソフトウェアとはかくあるべき」という込み入った話になります。
プログラムに秩序を与える¶
コンピューターが当たり前になった今の時代、より現実社会の物事に則したデータ構造を用いて表現できる幅を広げていく必要があります。プログラムでできる範囲が広くなればなるほど、1つのソフトウェアやシステムとして秩序を保つ方法が求められます。
オブジェクト指向の世界では、原則として「全てのデータや関数は何かしらのクラスに属する」必要があります。たとえば「name」という変数を宣言した場合、このnameは何の名前なのかを定義する必要があります。個人の名前なのか、建物の名前なのか、そういったことです。
関数でも同じことがいえます。get_total()
という関数がある場合、何の合計をゲットしているのかを定義しなければなりません。人数の合計なのか、売上の合計なのか。そのような形で定義します。
持っている属性を変数、可能な処理を機能として切り出して、それらの持ち主を抽象化して名前をつけたものがクラスとなります。
クラスの定義¶
こちらのイメージ図を見てください。
左側には色んな人のイラストがあります。性別も年齢も名前も各々違いますが、当たり前ですが「人間」という切り口で見た場合、各々が人間であると言えます。そのため、この例では左記のイラストで表現されているものは人間であるということで、抽象化してクラスとして定義しています。共通している属性をまとめてグルーピングして、そのグルーピングに対して名称をつけます。
ソースコードは以下のようになります。
class Human:
age = 0 # 年齢
last_name = '' # 姓
first_name = '' # 名前
blood_type = '' # 血液型
抽象化して「Humanクラス」をここでは定義しました。この抽象化されたモデルから、左記のイラストに該当する個別の人間を作れます。
# イラストに合わせて変数名を定義しました
office_lady = Human() # OL風の女性
salaryman = Human() # サラリーマン風の男性
senior = Human() # おじいさん
child = Human() # お子様
各々が人間なので人間として持っている共通属性を全て保有しています。OL風の女性もサラリーマン風の男性は、人間ではありますが各々が別の個人です。この、クラスの情報を全部持っている独立した個体のことをオブジェクトと言います。
抽象化した「人間」というモデルから、各々別の個体を作り出すイメージです。
Pythonは全てがオブジェクトです¶
Pythonはオブジェクト指向をサポートしている言語であり、同時に全てのデータの型がオブジェクトになっています。今まで登場してきた文字列/数値/リスト/辞書/タプルなど、これらは全てクラスから作られたオブジェクトです。
データ型 |
クラス名 |
---|---|
文字列 |
class str |
数値 |
class int |
リスト |
class list |
辞書 |
class dict |
タプル |
class tuple |
このような形で、Pythonで扱うデータは全てクラスが用意されてます。
オブジェクトの理解を深めるためにも、今まで利用してきたデータ型を「オブジェクトとして」振り返ります。利用イメージや便利さが伝わるでしょう。
クラスは変数と関数を持つことが可能¶
クラスには変数を定義する領域と、関数を定義する領域があります。 文字列クラス(class str)を例に取ると、代表的なものは以下の通りです。公式ドキュメントに、class strの情報がまとまって掲載されています。
参考: 文字列メソッド
あるクラスに属している関数のことを、オブジェクト指向の用語で**メソッド(method)あるいはメンバー関数と言います。 同様に、あるクラスに属している変数のことを、オブジェクト指向の用語でデータ属性(data attribute)**と言います。 メソッド、データ属性などをまとめて属性ということもあります。
オブジェクト.関数名¶
メソッドを呼び出す場合は、そのメソッドがどのクラスに属しているか明示する必要があります。その為「オブジェクト名.メソッド名」とドットでつなげています。
s.count('a')
を例に取ると、変数sは文字列(str)クラスのオブジェクトです。strクラスにはcount関数が定義されています。その為、s.count
という形でメソッドを呼び出すことが出来ます。
もし、変数sが文字列でなかった場合、「Attribute Error(属性エラー)」というエラーが発生します。countなんていう属性は無いから呼び出せないよ、という意味です。
データ属性の初期化(__init__
メソッド)¶
class Human:
age = 0 # 年齢
last_name = '' # 姓
first_name = '' # 名前
blood_type = '' # 血液型
上記のクラス定義から、このように一つひとつ値を入れると面倒です。
h = Human()
h.age = 33
h.last_name = '田中'
h.first_name = '一郎'
h.blood_type = 'O'
次のようにできると、1行で完結して便利ですね。
h = Human(33, '田中', '一郎', 'O')
Pythonでオブジェクトを生成する時には、__init__
という名称の関数(__init__
メソッド)が呼び出されます。
デフォルトでは何も処理しません。
Pythonは__(アンダースコア2つ)から始まる変数や関数は、そのクラス内でしか参照できなくなります。初期化する時は他のクラスからの影響を受けては困りますので、そのような配慮がなされています。
__init__
メソッドを定義してみましょう。
class Human:
def __init__(self, age, last_name, first_name, blood_type):
self.age = age # 年齢
self.last_name = last_name # 姓
self.first_name = first_name # 名前
self.blood_type = blood_type # 血液型
__init__
メソッドの第1引数のself¶
Pythonで理解が難しいことの1つが、このselfキーワードです。
Pythonではオブジェクトが利用する関数を定義する場合、第1引数はオブジェクト自身が自動的に代入される仕組みになっています。
Pythonのselfは、予約語ではありません。self以外の単語も使えますが、慣習としてselfが使われます。 selfという変数名の代わりに、元のオブジェクトの変数名を使う必要はありません。selfにした方が、誰にとってもわかりやすいでしょう。
インスタンス¶
クラスから作られたオブジェクトのことを、オブジェクト指向の用語でインスタンスといいます。 インスタンス固有のデータと、クラス自体のデータを定義できます。
クラス変数¶
クラス変数とは、クラス自体が保持する変数のことです。Pythonでは、原則としてクラス名の下に宣言された変数はクラス変数とみなされます。
class Sample1:
name = 'name' # クラス変数(クラス自体が保持する変数)
print(Sample1.name) # name
Sample1.name = 'changed_name'
print(Sample1.name) # changed_name
クラス名.変数名
あるいは、オブジェクト.変数名
の形式で利用できます。これがクラス変数です。
インスタンス変数¶
オブジェクト固有の変数のことです。selfキーワードで利用できます。クラス変数のことをクラス属性とも、インスタンス変数のことをデータ属性ともいいます。
class Sample2:
def __init__(self, value):
self.value = value
s1 = Sample2('AAA')
s2 = Sample2('BBB')
print(s1.value) # AAA
print(s2.value) # BBB
s1.value = 'CCC'
print(s1.value) # CCC
print(s2.value) # BBB
オブジェクトs1
が参照している値を変更しても、s2
の値には全く影響がありません。オブジェクト固有だからです。
クラス変数はクラスの中に、インスタンス変数はインスタンスの中に変数を持っています。
項目 |
意味 |
形式 |
---|---|---|
クラス変数 |
クラス自体が保持する変数 |
|
インスタンス変数 |
オブジェクト固有の変数 |
|
クラスで共通の値を使いたい場合は、クラス変数を使います。 インスタンスごとに、別々の値を使いたい場合は、インスタンス変数を使います。
公式ドキュメント¶
詳しくは クラス を参照ください。