はじめに
Everything is an object
Pythonは全てオブジェクトである。
以下のように数字は int というクラスで
文字列は str というクラスである。
a = 1
b = "abc"
type(a) # <class 'int'>
type(b) # <class 'str'>
Pythonのクラスは全てobjectというクラスから継承している。
object内の関数は全てDunderである。
Dunderとは
__init__
のようにアンダースコア2つに囲まれている関数のことを Dunder(Double underscore) と呼ぶ。
Special methods(特殊メソッド) 、 Magic methods ともいわれる。
Dunderの種類
基本的なメソッド
__init__(self[, ...])
インスタンスの初期化。インスタンスを生成すると実行される関数。
2番目 に実行される。 1番目ではなく、2番目です。
__new__(cls)
インスタンスの生成。インスタンス生成前に実行される関数。
1番目 に実行される。
__new__
を使用したときは、return super().__new__(cls)
をつけないと、__init__
が実行されない。
class Foo():
def __new__(cls):
print('foo new')
return super().__new__(cls)
def __init__(self):
print('foo init')
Foo()
class Foo2():
def __new__(cls):
print('foo2 new')
def __init__(self):
print('foo2 init')
Foo2()
foo new
foo init
foo2 new
__del__(self)
ファイナライザ、デストラクタ(正しくない)と呼ばれる。インスタンスが削除されるときに実行される。
__del__()
は、Pythonのガベージコレクション機能と一緒に使用され、不要なオブジェクトを削除するために自動的に呼び出される。
__del__()
はどのタイミングで呼び出されるかは保証されていない。del
によって絶対呼び出されるわけではない。また、__del__()
をオーバーライドすることは非推奨。
__repr__(self)
オブジェクトを表す公式の文字列を計算して返す。
repr() を実行することで呼び出される。
主にデバッグ用。
参考 : Pythonのstr( )とrepr( )の使い分け
__str__(self)
オブジェクトを表す(非公式の)表示に適した文字列を計算する。
str(), format(), print() などによって呼ばれる。
__str__
が 定義されていなければ、 __repr__
が呼ばれる。
class Person:
def __init__(self, first_name, family_name):
self.first_name = first_name
self.family_name = family_name
def __str__(self):
return f"{self.first_name}"
def __repr__(self):
return f"{self.first_name} {self.family_name}"
person = Person("Taro", "Yamada")
print(str(person)) # Taro
print(repr(person)) # Taro Yamada
__bytes__(self)
bytes() で呼び出される。
オブジェクトのバイト文字列表現を計算する。
__format__(self, format_spec)
format() によって呼ばれる。
何もフォーマット指定子を使用しない場合は、__str__()
が呼び出される。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __format__(self, format_spec):
if format_spec == 'short':
return f"{self.name}"
elif format_spec == 'long':
return f"{self.name} ({self.age})"
else:
return str(self)
def __str__(self):
return f"{self.name}は{self.age}歳です。"
person = Person("太郎", 20)
print("{:short}".format(person)) # 太郎
print("{:long}".format(person)) # 太郎 (20)
print("{}".format(person)) # 太郎は20歳です。
__hash__(self)
オブジェクトのハッシュ値を返すときに用いられる。
hash() によって呼び出される。
\_\_eq__
をオーバーライドしたときは \_\_hash__
もオーバーライドしなければならない。\_\_hash__
が Noneになってしまう。
参考 : Pythonでインスタンスを比較するために__eq__を実装するときの注意点
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __hash__(self):
return hash((self.name, self.age))
person1 = Person("Taro", 20)
person2 = Person("Jiro", 15)
person3 = Person("Taro", 20)
print(hash(person1)) # 5733229489180753685
print(hash(person2)) # -1653627169604865911
print(hash(person3)) # 名前と年齢が同じなので、hash値はperson1と同じ
__bool__(self)
bool() によって呼びだされる。
True か False を返さなければならない。
拡張比較メソッド
__lt__(self, other)
オブジェクトを<
で比較するときに使用される。
__le__(self, other)
オブジェクトを<=
で比較するときに使用される。
__eq__(self, other)
オブジェクトの等価性を比較するためのメソッド。
オブジェクトを==
で比較するときに使用される。
__ne__(self, other)
オブジェクトの非等価性を比較するためのメソッド。
オブジェクトを==
で比較するときに使用される。
__gt__(self, other)
オブジェクトを>
で比較するときに使用される。
__ge__(self, other)
オブジェクトを>=
で比較するときに使用される。
コード例
以下のように横の長さ、縦の長さの2つの属性を持つ長方形クラスを例に挙げる。
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def __eq__(self, other):
return self.width == other.width and self.height == other.height
def __ne__(self, other):
return not self == other
def __lt__(self, other):
return self.width * self.height < other.width * other.height
def __gt__(self, other):
return self.width * self.height > other.width * other.height
rect1 = Rectangle(2, 3)
rect2 = Rectangle(3, 4)
rect3 = Rectangle(2, 3)
print(rect1 == rect2) # False
print(rect1 == rect3) # True
print(rect1 != rect2) # True
print(rect1 < rect2) # True
print(rect2 > rect3) # True
比較拡張メソッドまとめ
比較拡張メソッド | 比較演算子 |
---|---|
__eq__ | == |
__ne__ | != |
__lt__ | < |
__le__ | <= |
__gt__ | > |
__ge__ | >= |
functools の total_orderingデコレータを使えば、 __lt__(), __le__(), __gt__(), __ge__() の中からどれか1つと、 __eq__() メソッドを定義するだけでいい。(速度は少し遅くなる)
参考 : 公式ドキュメント
属性値にアクセスするメソッド
__getattr__(self, name)
存在しない属性にアクセスしたとき、つまりAttributeErrorが発生するときに呼び出される。
__getattribute__(self, name)
インスタンスのすべての属性にアクセスするときに呼び出される。
AttributeError の発生とは関係なく、class.attr を使ったすべての属性アクセスの時に動作する。
sys.audit()
でアクセスイベントをログに記録することができる。
__setattr__(self, name, value)
属性の代入がされたときに呼び出される。sys.audit()
でアクセスイベントをログに記録することができる。
__delattr__(self, name)
属性の削除がされたときに呼び出される。sys.audit()
でアクセスイベントをログに記録することができる。
__dir__(self)
dir() によって呼び出される。dir() はオブジェクトが持つ属性のリストを返す。
class Person:
def __init__(self, name):
self.name = name
p = Person("Taro")
print(dir(p))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__', 'name']
【参考】PEP 562 -- Module getattr and __dir__を試してみた
ディスクリプタ
ディスクリプタとは以下の3つのメソッドを持つクラスである。(より詳細な内容は別の記事にまとめる予定。)
__get__(self, instance, owner=None)
インスタンスの属性取得時に呼び出される。
以下の例では、objのパラメータにはAのインスタンス(a)が入る。
selfにはBのインスタンス(b)が、objectにはAのクラスが入る。
class B:
def __get__(self, obj, objtype=None):
print(obj.arg1)
print(obj.arg2)
return 'Hello, world!'
class A:
b = B()
def __init__(self, arg1, arg2):
self.arg1 = arg1
self.arg2 = arg2
a = A("foo", "hoge")
print(a.b)
foo
hoge
Hello, world!
__set__(self, instance, value)
オーナークラスのインスタンスの属性を設定する際に呼び出される。
__delete__(self, instance)
オーナークラスのインスタンスの属性を削除する際に呼び出される。
コンテナのエミュレート
Pythonにおいて、コンテナとは、複数の要素を格納するオブジェクトのことを指す。(リスト、タプル、セット、辞書など)
コンテナの動作をエミュレートするとは、Pythonの特殊メソッドを使用して、オブジェクトがコンテナのように振る舞う(要素の追加、削除、検索、スライシングなど)ようにすること。
__len__(self)
len() によって呼び出される。0以上の整数で返す。
__getitem__(self, key)
self[key]
によって呼び出される。
__setitem__(self, key, value)
self[key]
に値を代入するときに呼び出される。
__delitem__(self, key)
self[key]
を削除するときに呼び出される。
__iter__(self)
イテレータオブジェクトを返す。iter() によって呼び出される。
また、 for i in x
では x の iter() を呼び出す。
参考 : __iter__()はイテレータを返し、__next__()は次の要素を返す
__next__(self)
next() によって呼び出される。
__next__()
を呼び出すと、イテレータは次の値を返す。
参考 : __iter__()はイテレータを返し、__next__()は次の要素を返す
__reversed__(self)
reversed() によって呼び出される。
コンテナ内の全要素を逆順にしたイテレータを返す
__contains__(self, item)
in が使われるときに呼び出される。
帰属テスト演算子を実装するために呼び出される。 item が self 内に存在する場合にTrue
を、そうでない場合にはFalse
を返す。
その他
数値型をエミュレートする\_\_add__()
, \_\_sub__
, \_\_and__
, \_\_or__
など他にも色々特殊メソッドは存在する。以下の公式ドキュメントにまとまっているので、そちらを参考にしてください。
まとめ
メソッド名 | 説明 | 呼び出す関数例 |
---|---|---|
__init__(self[, args...]) |
インスタンス生成直後に呼び出される。 | obj = MyClass(arg1, arg2) |
__new__(self) |
インスタンス生成直前に呼び出される。 | obj = MyClass() |
__del__(self) |
インスタンスが削除される際に呼び出される。 | del obj |
__repr__(self) |
オブジェクトの(公式の)文字列を返す。 | repr(obj) |
__str__(self) |
オブジェクトを表示に適した文字列を返す。 | str(obj) |
__bytes__(self) |
インスタンスをバイト列に変換するために呼び出される。 | bytes(obj) |
__hash__(self) |
インスタンスのハッシュ値を返すために呼び出される。 | hash(obj) |
__bool__(self) |
インスタンスを真偽値に変換するために呼び出される。 | bool(obj) |
__eq__(self, other) |
2つのオブジェクトが等しいかどうかを判断する。 | obj1 == obj2 |
__ne__(self, other) |
2つのオブジェクトが異なるかどうかを判断する。 | obj1 != obj2 |
__lt__(self, other) |
self がother よりも小さい場合にTrue を返す。 |
obj1 < obj2 |
__le__(self, other) |
self がother 以下の場合にTrue を返す。 |
obj1 <= obj2 |
__gt__(self, other) |
self がother よりも大きい場合にTrue を返す。 |
obj1 > obj2 |
__ge__(self, other) |
self がother 以上の場合にTrue を返す。 |
obj1 >= obj2 |
__get__(self, instance, owner) |
ディスクリプタによる属性取得時に呼び出される。 | obj.attr |
__set__(self, instance, value) |
ディスクリプタが属性の値を設定するときに呼び出される。 | obj.attr = value |
__delete__(self, instance) |
ディスクリプタが属性を削除するときに呼び出される。 | del obj.attr |
__iter__(self) |
イテレータオブジェクトを返し、for ループでオブジェクトを反復処理するためのメソッド。 |
for item in obj ,iter()
|
__next__(self) |
イテレータオブジェクトの次の要素を返すためのメソッド。 | next(obj) |
__call__(self[, args...]) |
オブジェクトを関数のように呼び出すことができるようにするためのメソッド。 | obj(args) |
__reversed__(self) |
オブジェクトを逆順にしたイテレータを返す。 | reversed() |
__contains__(self, item) |
オブジェクトの中にitemがあればTrue を返す。 |
item in obj |
__len__(self) |
オブジェクトの長さを返す。 | len(obj) |
__getitem__(self, key) |
インデックスまたはキーに基づいてオブジェクトの要素を取得する。 | obj[key] |
__setitem__(self, key, value) |
インデックスまたはキーに基づいてオブジェクトの要素を設定する。 | obj[key] = value |
__delitem__(self, key) |
インデックスまたはキーに基づいてオブジェクトの要素を削除する。 | del obj[key] |
__add__(self, other) |
+ 演算子を使用してオブジェクトを追加する。 |
obj1 + obj2 |
__sub__(self, other) |
- 演算子を使用してオブジェクトを減算する。 |
obj1 - obj2 |
__mul__(self, other) |
* 演算子を使用してオブジェクトを乗算する。 |
obj1 * obj2 |
__truediv__(self, other) |
/ 演算子を使用してオブジェクを除算する。 |
obj1 / obj2 |
__and__(self, other) |
ビット単位のAND演算を行う。 | obj1 & obj2 |
__or__(self, other) |
ビット単位のOR演算を行う。 | obj1 | obj2 |
__xor__(self, other) |
ビット単位のXOR演算を行う。 | obj1 ^ obj2 |