Pythone クラス

クラス作成

クラス定義

class Person:
class Person():
class Person(obuject):

Python2ではクラス名のあとに(object)が必要だった
Python3では()だけ、()なしも可能
(object)を書くとクラス継承のベースクラスと使えるようになる

メソッド

関数定義と同じdefを使い、引数の最初の引数としてselfを書く。
selfはオブジェクト自身を指す。

# クラス定義
class Person(object):
    def say_something(self):
        print('hello')

# 実行
person = Person()             # オブジェクトを生成
person.say_something()        # メソッド呼び出し

初期化処理

初期化処理は、__init__というメソッドの中で定義する。
__init__のことをコンストラクタという。

class Person(object):
    def __init__(self):
        print('First')

person = Person()    # 'First'

オブジェクトが初期化されるときに引数を渡す。
引数で受け取った値をself.nameに入れて保存する。
self.nameのようにオブジェクト自身が持っている変数のことをインスタンス変数という。

class Person(object):

    # 初期化処理
    # 引数を渡すようにするとオブジェクト作成時に引数を渡さないとエラーになる
    # これを回避するには、ディフォルト引数を指定して省略可能にする。
    def __init__(self, name='Default'):
        self.name = name  # インスタンス変数に保存
        print(self.name)

    # メソッド定義
    # self.nameは__init__の中で値を保持するので、他のメソッドから呼び出せる
    def say_something(self):
        print('I am {}. hello'.format(self.name))
        self.run(10)  # selfを使うとメソッドの中からクラスのメソッドが呼び出せる

    # メソッド
    def run(self, num):
        print('run' * num)

# 実行
person = Person('Mike')    # 'Mike'
person.sya_something()     # 'I am Mike. hello'
                           # runrunrunrunrunrunrunrunrunrun

終了処理

終了処理は__del__を使って書く。
最後に実行される処理のことをデストラクタという。
デストラクタはオブジェクトがもう使われなくなったタイミングで呼び出される。

class Person(object):
    def __init__(self, name):
        self.name = name

    def __del__(self):
        print('good bye')

person = Person('Mike')
print('##########')
##########
good bye

print(‘##########’)のあとにコードがなく、オブジェクトがもう使われないので、printの処理が実行されたあとにデストラクタの処理が実行される。

明示的にデストラクタを呼び出す

明示的にデストラクタを呼び出したい場合は、delを使ってオブジェクトを消す。

person = Person('Mike')
del person
print('##########')
good bye
##########

クラス継承

継承

継承は既存のクラスを引き継いで新たなクラスを作るものです。

# 親クラス
class Car(object):
    def run(self):
        print('run')

# 継承クラス
class MyCar(Car):
    pass            # pasと書くと何もしないクラスを作成できる

# もう一つ継承クラスを作成
class AdvancedCar(Car):
    def auto_run(self):
        print('auto run')

# 実行
# 親クラスを実行
car = Car()
car.run()        # run

# 一つ目の継承クラスを実行
my_car = MyCar()
my_car.run()     # run 親クラスのurn()が実行される

# もう一つの継承クラスを実行
advanced_car = AdvancedCar()
advanced_car.run()             # 'run' 親クラスのrun()が実行される
advanced_car.auto_run()        # 'auto run' 独自のメソッドを実行 

継承元メソッドの上書き

継承元のメソッドを継承先のクラスで再度定義することで処理の上書きができる。
これをメソッドのオーバーライドという。

# 親クラス
class Car(obuject):
    def run(self):
        print('run')

# 一つ目の継承クラス
class MyCar(Car):
    # オーバーライド
    def run(self):
        print('fast')

# 二つ目の継承クラス
class AdvancedCar(Car):
    # オーバーライド
    def run(self):
        print('super fast')

# 実行
car = Car()
car.run()
print('##########')

my_car = MyCar()
my_car.run()
print('##########')

advanced_car = AdvancedCar()
advanced_car.run()
run
##########
fast
##########
super fast

継承元のメソッドを呼び出す

superを使って継承元のメソッドを呼び出すことができる。
superは継承元のクラスを指している。

# 親クラス
class Car(obuect):
    # 初期化処理
    def __init__(self, model=None):
        self.model = model

# 継承クラス
class AdvancedCar(Car):
   # 初期化処理をオーバーライド
   def __init__(self, model='SUV', enable_auto_run=False):
        # オーバーライドすると継承元の__init__は実行されなくなる
        # superは継承元のクラスを指しているので、継承元の初期化処理を呼び出す
        super().__init__(model)

        # 親クラスの初期化処理後、自身の初期化処理を実行
        self.enable_auto_run = enavle_auto_run

# 実行
advanced_car = AdvancedCar('sedan', 'SUV')
# 親クラスのインスタンス変数を呼び出すことができる。
# super().__init__(model)で初期化されている。
print(advanced_car.model)         # 'sedan'

# 自身のインスタンス変数の呼び出し
print(advanced_car.auto_run)      # 'SUV'

プロパティ・セッター

プロパティ

オブジェクト変数を勝手に書き換得られたくない場合プロパティを使う。
プロパティを使うには変数の前に「_」(アンダースコア)を付ける

ゲッター

クラスの変数を返すだけのメソッドを定義し、その上に「@property」というデコレーターを加える。
@propertyが付いた定義をプロパティのゲッターと呼ぶ。

# 親クラス定義
class Car(object):
    def __init__(self, model=None):
        self.model = model

# 子クラス定義
class AdvancedCar(Car):
    # 初期化
    def __init__(self, model='SUV', enable_auto_run=False):
        # 親の初期化処理
        super().__init__(model)
        # プロパティで使えるように変数名にアンダーバーを付ける
        self.__enable_auto_run = enable_auto_run = True
        print(advanced_car._enable_auto_run)

    # プロパティ
    # クラスの変数の値を返すメソッド
    # @propertyが付いた定義をプロパティのゲッターと呼ぶ
    @property
    def enable_auto_run(self):
        return self._enable_auto_run

# 実行
advanced_car = AdvancedCar('SUV')
print(advanced_car.enable_auto_run)    # False
セッター

@プロパティ名.setterのデコレーターを付けた定義をセッターと呼ぶ。
プロパティに値を設定できます。

# 親クラス定義
class Car(object):
    def __init__(self, model=None):
        self.model = model

# 子クラス定義
class AdvancedCar(Car):
    # 初期化
    def __init__(self, model='SUV', enable_auto_run=False):
        # 親の初期化処理
        super().__init__(model)
        # プロパティで使えるように変数名にアンダーバーを付ける
        # アンダーバー1つの場合、外部から参照できる。2つ(__)は参照不可。
        self.__enable_auto_run = enable_auto_run

    # プロパティ
    # クラスの変数の値を返すメソッド
    # @propertyが付いた定義をプロパティのゲッターと呼ぶ
    @property
    def enable_auto_run(self):
        return self.__enable_auto_run

    # セッター
    @enable_auto_run.setter
    def enable_auto_run(self, is_enable):
        self.__enable_auto_run = is_enable

# 実行
advanced_car = AdvancedCar('SUV')
advanced_car.enable_auto_run = True
print(advanced_car.enable_auto_run)    # True

ダックタイピング

ダッグタイピングは、「もしそれが鳥のように鳴き、歩き、泳ぎ、そして羽毛で覆われているのであれば、それはおそらくアヒルである」という有名な引用に由来している。
オブジェクトがどのクラスに属しているかではなく、そのオブジェクトが持つ属性やメソッドに基づいて処理を行うという考え方である。

ダックタイピングの例

class Duck:
    def speak(self):
        print("ガァガァ")

class Cat:
    def speak(self):
        print("ニャ~")

# 関数call_speak()
# 引き渡されたオブジェクトがどのクラスに属しているかを気にしない
# 代わりにspeakメソッドが呼び出されることを期待している。
# DuckクラスとCatクラスはそれぞれspeakメソッドを持っているたcall_speak関数で
# 処理ができる。
def call_speak(animal):
    animal.speak()

duck = Duck()
cat = Cat()

call_speak(duck)   # ガァガァ
call_speak(cat)    # ニャ~

活用例

# open関数はファイルオブジェクトを返すが、
# オブジェクトがどのような型で刈るかについては気にしない。
# 必要なのは、readメソッドがオブジェクトに実装されていることだけ。
with open("file.txt") as f:
    contents = f.read()
    # 処理

抽象クラス

抽象クラスは、共通の振る舞いを持つクラスの基盤を提供し、それを継承することで具体的な実装を行うことを促す。

抽象クラスはabc(Abstract Base Classes)モジュールを使い定義できる。
抽象クラスは、そのクラス自体から直接オブジェクトを作成することはできず、サブクラスで実装されるメソッドや属性を定義するための基本的な設計要素です。

from abc import ABCMeta
from abc imoprt abstractmethod

# 抽象クラスvehicleの定義
class vehicle(metaclass = ABCMeta):
    @abstractmethod
    def start(self):
        pass
    @abstractmethod
    def stop(self):
        pass

# vehicleを継承したクラスcarの定義
class car(vehicle):
    def start(self):
        print("car start.")
    def stop(self):
        print("car stop")

# vehicleを継承したクラスmothrcycleの定義
class motorcycle(veicle):
    def start(self):
        print("moto start.")
    def stop(self):
        print("moto stop")

# 実行
if __name__ == "__main__":
    mycar = car()
    mycar.start()
    cycar.stop()

多重継承

2つのクラスの機能をあわせ持つクラスを作成したい場合は、「,」(カンマ)でつないで複数のクラスを継承する。

継承元クラスに同じ名前のメソッドがあった場合は、クラス継承時に左側にあるクラスのメソッドが優先して実行される。

# 継承元1つめのクラス
clas Person(object):
    def talk(self):
        print('talk')

    def run(self):
        print('person run')

# 継承元2つめのクラス
class car(object):
    # 継承元1つめのクラスと重複するメソッド
    def run(self):
        print('car run')

# 多重継承クラス
class PersonCarRobot(Person, Car):
    def fly(self):
        print('fly)

# 実行
person_car_robot = PersonCarRobot()
person_car_robot.run()               # 'person run'

クラス変数

クラス変数を使うと、どのオブジェクトでも同じ値を共有できる。
クラス変数を作成するには、クラスのインデント内で変数を宣言する。

class Person(object):

    # クラス変数宣言
    kind = 'human'

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

    def who_are_you(self):
        print(self.name, self.kind)

クラスメソッド

クラスメソッドは、各インスタンスに紐づかせるインスタンスメソッドに対して、クラスそのものを紐づかせるためのメソッド。
インスタンスメソッドはインスタンスを介してアクセスすることができるが、クラスメソッドはクラスを介して直接アクセスすることができる。

class Person(object):
    kind = 'human'     # クラス変数

    def __init__(self):
        self.x = 100

    # クラスメソッド
    @classmethod                 # デコレーター「@classmethod」を付ける
    def what_is_your_kind(cls):  # selfではなくclsを指定
        return cls.kind

# 実行
a = Person()  # aにはオブジェクトが格納される
print(a.what_is_your_kind())    # human  

b = Person    # bはクラスそのものが入っている
print(a.what_is_your_kind())    # human

スタティックメソッド

「@staticmethod」を付けて作成したメソッドは、引数にselfもclsも取らない。
このメソッドをスタティックメソッドという。

class Person(obect):

    @staticmethod      # デコレーター「@staticmethod」を付ける
    def about():       # selfもclsも取らない
        print('about human')

# 実行
Person.about()         # 'about human'

スタティックメソッドはクラスのデータにアクセスすることがなく、クラスとの関連性が薄いので、クラスの外側に関数として作成しても問題ない。
しかし、クラスに関連があるような処理であることを示したい場合、スタティックメソッドとして作成する理由が出てくる。

特殊メソッド

前後に「_」(アンダースコア)が2つ付いているものを特殊メソッドといい、特別な意味を持つ。
__init__も特殊メソッドのひとつ。

__str__

オブジェクトの文字列表現を返すメソッド。
何かのオブジェクトをprint関数の引数にすると、__str__メソッドの結果を返す。

class Word(object):
    def __init__(self, text):
        self.text = text

    def __str__(self):
        return 'word!!!!!!'

w = Word('test')
print(w)           # 'word!!!!!!'

__len__

__len__は変数の長さを返す。
文字列はリストの長さをlen関数で調べられるのは、それらの__len__メソッドが内部的に呼び出されているからである。

class Word(object):
    def __init__(self, text):
        self.text = text

    def __len__(self):
        return len(self.text)

w = Word('test')
print(len(w))          # 4

__add__

クラスのオブジェクトが足しあわされたときに実行される特殊メソッド。
引数にもう一つのオブジェクトを取り、それらが足しあわされたときの処理を決める。

class Word(object):
    def __init__(self, text):
        self.text = text

    def __add__(self, word):
        return self.text.lower() + word.text.lower()  # 小文字に変換して結合

w = Word('TEST')
w2 = Word('##########')
print(w + w2)             # 'test##########'

__eq__

クラスが==で比較されたときの処理を記述。
自分で定義したクラスの2つのオブジェクトを単純に==で比較するとFalseが返ってくる。
これはオブジェクトのidが異なる為である。

class Word(object):
    def __init__(self, text):
        self.text = text

    def __eq__(self, word):
        # クラスのインスタンスが保持しているtextを小文字にして比較
        return self.text.lower() == word.text.lower()

w = Word('test')
w2 = Word('test')
print(w == w2)  # True

コメント

タイトルとURLをコピーしました