Python : クラス-1

参考書籍 : Python実践入門


Pythonのクラス機構
クラス定義の構文は、以下のようになる。

# class クラス名(基底クラス名):
#   def メソッド名(引数1, ...):
#       処理
#

基底クラスの指定は()も含めて省略でき、省略した場合はobjectクラスを継承する。
関数にはメソッドとプロパティをもたせることができる。
プロパティは__init__()内でselfを使用して定義する。

class Page(object):
    def __init__(self, num, content):
        self.num = num  # property
        self.content = content

    # method
    def output(self):
        return f'{self.content}'

>>> Page
<class '__main__.Page'>

 


インスタンスの生成
クラスオブジェクトに()をつけて呼び出すと、インスタンスを作成できる。

title_page = Page(0, 'Python Practice Book')
print(type(title_page))  # <class '__main__.Page'>
print(isinstance(title_page, Page))  # True
print(dir(title_page))  # ['__class__', ... 'content', 'num', 'output']

 


インスタンスメソッドの呼び出し
クラス定義の中で定義されたメソッドは、クラスがインスタンス化することにより、インスタンスメソッドとして呼び出せる。
インスタンスメソッドは第一引数で受け取るselfを使い、インスタンス自身にアクセスできる。

print(title_page.output())  # Python Practice Book

 


・__new__()と__init__()の違い
Pythonにおけるコンストラクタは__new__()で、__init__()はイニシャライザと呼ばれる。
コンストラクタ__new__()はコンストラクタを生成する処理を担当し、
イニシャライザ__init()__はインスタンス生成後の初期化を行う。
__new__()の戻り値がクラスのインスタンスとなる。

class Klass(object):
    def __new__(cls, *args):  # コンストラクタ
        print(f'{cls=}')
        print('new', args)
        return super().__new__(cls)

    def __init__(self, *args):
        print('init', args)

kls = Klass(1, 2, 3)
# new (1, 2, 3)
# init (1, 2, 3)

 


・プロパティ
@propertyを使い、メソッドに()なしでアクセスできる。

class Book(object):
    def __init__(self, raw_price):
        if raw_price < 0:
            raise ValueError('price must be positive')
        self.raw_price = raw_price
        self._discounts = 0

    @property
    def discounts(self):
        return self._discounts

    @discounts.setter
    def discounts(self, value):
        if value < 0 or 100 < value:
            raise ValueError('discounts must be between 0 and 100')
        self._discounts = value

    @property
    def price(self):
        multi = 100 - self._discounts
        return int(self.raw_price * multi / 100)


book = Book(2000)
print(book.discounts)  # 0
print(book.price)  # 2000
book.discounts = 20
print(book.price)  # 1600
book.discounts = 120  # ValueError: discounts must be between 0 and 100

discounts()とprice()には@propertyがついており、()なしで呼び出せる。
@propertyがついたメソッドはゲッターと呼ばれ、値を取得するために呼び出される。
@discounts.setterがついたメソッドはセッターと呼ばれ、book.discounts = 20のように値を代入するときに呼び出される。
代入と同時にエラーチェックを行っている。
@price.setterは存在しないため、book.price = 100のような操作はAttributeErrorとなる。

クラスBook内で、_discountのようにプロパティの頭文字にアンダースコアをつけるときは、プライベート変数として使用することを表現している。

__xのように、アンダースコア2つをつけると、名前修飾が行われる。
名前修飾は、Klassクラスの変数__xをKlass__xという名前に変換する機能である。
この機能は、サブクラスでの名前衝突を避けるため使われる。