はじめに
pythonの基礎として、classについて記載していきたいと思います。
classの基本
クラスを「オブジェクトの設計書」と言っている学習書が多いようですが、どんなオブジェクトを作るのかその仕様を定義するのがクラスです。そしてこのクラスから作られたオブジェクトのことをインスタンスと呼びます。
先日モジュールについても投稿しましたが、classにおいては、処理機能の操作や設定変更が外部からでも可能な点はモジュールとは異なる点です。
classを使うことで新しくオブジェクトを生成することが出来ます。
基本的な構文はこのようになっています。
classに続けて、任意のクラス名を指定できます。クラス名の先頭は大文字です。
内部ではdefでメソッドを記述していきます。
>>> class ClassName():
... def __init__(self, ):
... hogehoge
引数にselfと書いていますが、pythonではメソッドは最低1つの引数を持つことが必須のためselfを引数に記載します。文字通りインスタンス自身をさします。
selfを使用することで、オブジェクト自身の変数を取得したり、メソッドを呼び出すことが出来ます。
コンストラクタ
上記にあるようにクラス内部に__init__
と書かれています。これをコンストラクタと言います。
コンストラクタは、インスタンスを作成する際にデータについて定義を行う重要な役割を果たすもので、データの初期化などを行います。
>>> class Test_class():
... def __init__(self, msg):
... self.value = msg
...
>>>
>>> instance = Test_class("Hello_world!")
>>> print(instance)
<__main__.test_class object at 0x10622e208>
>>> print(instance.value)
Hello_world!
コンストラクタの引数にselfとmsgを指定し、msgをvalueという属性(アトリビュート)に代入しています。
コンストラクタとは逆に、インスタンスが不要になり削除される時に呼ばれるメソッドをデストラクタと言います。デストラクタは__del__
という名前のメソッドで定義されます。
メソッドとは
メソッドとは、クラス内で定義された関数のことです。
以下のコードをご覧ください。
>>> class Test():
...
... def __init__(self, num1,num2,num3):
... self.num1 = num1
... self.num2 = num2
... self.num3 = num3
...
... def print_sumall(self):
... sumall = self.num1+self.num2+self.num3
... print(sumall)
...
>>> myinstance = Test(1,2,3)
>>> myinstance.print_sumall()
6
Testという名前のクラスを定義しま,コンストラクタとprint_sumallというメソッドを含んでいます。
コンストラクタにおいて属性num1、num2、num3に代入を行い、最終行のprint_sumallは生成したインスタンスが持つ属性三つの合計を出力しています。
継承とは
あるクラスを元にその派生クラスを作りる場合に継承を利用します。
>>> class Oya:
... def __init__(self,num1,num2,num3):
... self.num1 = num1
... self.num2 = num2
... self.num3 = num3
... def print_sumall(self):
... sumall = self.num1+self.num2+self.num3
... print(sumall)
...
>>> class Kodomo(Oya):
... def print_test(self):
... print("Oyaの継承")
... super().print_sumall()
...
>>> test = Kodomo(5,4,3)
>>> test.print_test()
Oyaの継承
12
Oyaクラスを元にKodomoクラスを継承で作成しました。
Kodomoクラスの引数に、Oyaクラスを渡し、親のクラスのメソッドを呼び出すのにsuper()を使います。
Kodomoクラスはprint_testというメソッドに加え、Oyaクラスのprint_sumallを呼び出すことができます。
カプセル化
オブジェクト指向プログラミングで重要な要素の一つがカプセル化です。
pythonでは変数やメソッドの名前の前に__(_を2つ)
をつけることによりprivateにすることができます。
つまりカプセル化により属性の読み書きやメソッドの呼び出しを制限(アクセス制御)することができます。
>>> class Area():
... def __init__(self, name):
... self.name = name;
... def self_introduction(self):
... print("私の出身は{}です".format(self.name))
...
>>> area = Area("千葉")
>>> area.self_introduction()
私の出身は千葉です
>>> area.name = "千葉"
>>> area.self_introduction()
私の出身は千葉です
このように、属性に直接アクセスして値を書き換えています。つまり基本的に全てのメソッドや属性は公開されており、外部からも直接アクセスすることができます。
一方で外部に公開したくないものや外部から直接操作したくないものには制御をつける必要があります。
プライベート変数
直接のアクセスを禁止するためには非公開属性を使用します。非公開属性は、メンバ変数(インスタンスに属する変数のこと)の先頭に"__"を付けることによりプライベート変数として定義できます。つまりアクセス制御ができます。
>>> class Area():
... def __init__(self, name1, name2):
... self.name1 = name1
... self.__name2 = name2
... def self_introduction(self):
... print("私の出身は{}で、{}生まれです。".format(self.name1,self.__name2))
...
>>> area = Area("千葉","昭和")
>>> area.self_introduction()
私の出身は千葉で、昭和生まれです。
>>>
>>> area.name1 = ("埼玉")
>>> area.self_introduction()
私の出身は埼玉で、昭和生まれです。
>>>
>>> area.name2 = ("平成")
>>> area.self_introduction()
私の出身は埼玉で、昭和生まれです。
このように通常のメンバ変数のみ変更されて、プライベート変数は変更できないようにすることができます。
クラス変数
クラス変数はクラス(インスタンスでは無く)に属する変数のことを言います。インスタンスに属するメンバ変数との違いは、クラス変数は全てのインスタンスで共有されるというところです。
>>> class Birth():
... age = 32;
... def __init__(self, area):
... self.area = area
... Birth.age += 1
... def get_age(self):
... return Birth.age
...
>>> birth1 = Birth("千葉")
>>> print(birth1.get_age())
33
>>> birth2 = Birth("埼玉")
>>> print(birth2.get_age())
34
新規のインスタンスを作成する度にクラス変数がインクリメント(1増加)されています。つまりクラス変数はインスタンスが違っても共有されています。
プライベートクラス変数の定義の仕方は、プライベート変数と同様に"__"を付けます。
>>> class Birth():
... __age = 32;
... def __init__(self, name):
... self.name = name
... Birth.__age += 1
... def get_age(self):
... return Birth.__number
...
>>> birth1 = Birth("千葉")
>>> print(birth1.get_age())
33
>>> birth2 = Birth("埼玉")
>>> print(birth2.get_age())
34
>>> print(Birth.__age)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Birth' has no attribute '__age'
このように外部からクラス名.クラス変数名のようにアクセスするとエラーが発生します。プライベートになっています。
外部からアクセスしたい場合は前回のget_ageのようにメソッドで定義しなければなりません。
おわり
長くなってきたのでプライベートメソッドに関しては今回は割愛します。