AnDeriensのブログ

個人的なブログです

Python文法学習 - クラス編

Pythonの文法キャッチアップノート。

クラス

Python において、クラスもオブジェクトである。

継承が何も定義されていない場合は、objectを継承している

class Foo:
  pass
class Foo(object):
  pass

プロパティ

クラス内で定義された変数は、クラス属性

特殊属性

クラスのメタ情報にアクセスするためのプロパティ。 __xx__ の形式で定義されている。

  • __name__
  • __module__
  • __dict__
  • __bases__
  • __doc__
  • __annotations__
class Foo:
  """
  Fooはbarをhogeするクラス
  """
  bar: int = 1

foo = Foo()
foo.__class__.__name__ # 'Foo'
foo.__class__.__module__ # '__main__'
foo.__class__.__dict__ # mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None})
foo.__class__.__bases__ # (<class 'object'>,)
foo.__class__.__doc__ # 'Fooはbarをhogeするクラス'
foo.__class__.__annotations__ # {'bar': <class 'int'>}

特殊メソッド

  • __new__ : インスタンス化時に呼ばれる。
  • __init__: インスタンス化後、初期化時に呼ばれる
  • __del__: オブジェクトが破棄されるときに呼ばれる

itmediaさんのサンプルコードを使わせてもらってます。

class Foo:
    def __new__(cls):
        print('__new__')
        self = super().__new__(cls)  # インスタンス生成を行う典型的なコード
        self.attr = 'set in __new__'  # ここでしかできない初期化処理を書いてもよい
        return self  # 生成したインスタンスを返す

    def __init__(self, name='foo'):
        print('__init__')
        self.name = name  # インスタンスの初期化処理

    def __del__(self):
        #super().__del__()  # 基底クラスに__del__メソッドがあれば必ず呼び出す
        print('__del__')  # インスタンスが破壊されるときに行う処理

foo = Foo()  # '__new__'と'__init__'が表示される
print('foo.attr:', foo.attr)  # 'foo.attr: set in __new__'
bar = foo
print('bar.name:', bar.name)  # 'bar.name: foo'
print('del foo')  # この時点ではまだ生成したインスタンスには別名がある
del foo
print('del bar')
del bar  # '__del__':この時点でインスタンスを束縛する名前がなくなる
  • __repr__: オブジェクトを表す「公式な」文字列。これは同じ値のオブジェクトを再生成するのに使える、有効な Python 式のようなものであるべきですとドキュメントに書かれているように、evalで呼び出して同じオブジェクトが生成されるのがいい。
  • __str__: オブジェクトを表す「非公式な」文字列
  • __bytes__: bytesで返されるオブジェクトのバイト文字列表現。 .encode('utf-8')した値を返すとbytes型で返せる。 (適切な環境が与えられれば) 。未実装で呼び出されるとエラー
  • __format__: format()等の関数で呼び出される、オブジェクトのフォーマット化された文字列表現。未実装で呼び出されるとエラー
class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age})"

    def __str__(self):
        return '%sという名前の%i歳の人' % (self.name, self.age)

    def __bytes__(self):
        return 'person'.encode('utf-8')

    def __format__(self, fmt):
        if len(fmt) == 0:
            return str(self)
        return fmt.format(self.name)


p = Person(name="anderiens", age=25)

print(p) # anderiensという名前の25歳の人
print(repr(p)) # Person(name='anderiens', age=25)
print(bytes(p)) # b'person'
print(format(p, '{} hoge')) # anderiens hoge

# reprをevalする
print(eval(repr(p))) # anderiensという名前の25歳の人

比較

  • __lt__: x < yで呼び出される
  • __le__: x <= yで呼び出される
  • __eq__: x == yで呼び出される
  • __ne__: x != yで呼び出される
  • __gt__: x > yで呼び出される
  • __ge__: x >= yで呼び出される
  • __hash__
  • __bool__

https://www.yoheim.net/blog.php?q=20171002 のコードを参考にさせてもらっています。

class Item:
    """
    価格順で並び替えできる
    """

    def __init__(self, price: int):
        self.price = price

    def __eq__(self, other):
        if not isinstance(other, Item):
            return NotImplemented
        return self.price == other.price    

    def __lt__(self, other):
        if not isinstance(other, Item):
            return NotImplemented
        return self.price < other.price

    def __ne__(self, other):
        return not self.__eq__(other)

    def __le__(self, other):
        return self.__lt__(other) or self.__eq__(other)

    def __gt__(self, other):
        return not self.__le__(other)

    def __ge__(self, other):
        return not self.__lt__(other)


item1 = Item(price=100)
item2 = Item(price=200)

if item1 > item2:
    print('item1 is more expensive than item2.')
else:
    print('item2 is more expensive than item1.')

参考

3. データモデル — Python 3.11.3 ドキュメント

[Pythonチートシート]特殊メソッド編:Pythonチートシート - @IT