Python Language
オーバーロード
サーチ…
マジック/ダンダーメソッド
PythonのMagic(double-underscoreの略語としてのdunderとも呼ばれる)メソッドは、他の言語の演算子オーバーロードと同様の目的を果たします。それらは、クラスが単項演算子式または2項演算子式のオペランドとして使用されるときに、クラスの振る舞いを定義することを可能にします。また、組み込み関数によって呼び出される実装としても機能します。
この2次元ベクトルの実装を考えてみましょう。
import math
class Vector(object):
# instantiation
def __init__(self, x, y):
self.x = x
self.y = y
# unary negation (-v)
def __neg__(self):
return Vector(-self.x, -self.y)
# addition (v + u)
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
# subtraction (v - u)
def __sub__(self, other):
return self + (-other)
# equality (v == u)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# abs(v)
def __abs__(self):
return math.hypot(self.x, self.y)
# str(v)
def __str__(self):
return '<{0.x}, {0.y}>'.format(self)
# repr(v)
def __repr__(self):
return 'Vector({0.x}, {0.y})'.format(self)
さまざまな式でVector
クラスのインスタンスを自然に使用できるようになりました。
v = Vector(1, 4)
u = Vector(2, 0)
u + v # Vector(3, 4)
print(u + v) # "<3, 4>" (implicit string conversion)
u - v # Vector(1, -4)
u == v # False
u + v == v + u # True
abs(u + v) # 5.0
コンテナおよびシーケンス型
キーまたはインデックスによる値へのアクセスをサポートするコンテナタイプをエミュレートすることは可能です。
メモリを節約するためにゼロ以外の要素だけを格納するスパースリストのこの単純な実装を考えてみましょう。
class sparselist(object):
def __init__(self, size):
self.size = size
self.data = {}
# l[index]
def __getitem__(self, index):
if index < 0:
index += self.size
if index >= self.size:
raise IndexError(index)
try:
return self.data[index]
except KeyError:
return 0.0
# l[index] = value
def __setitem__(self, index, value):
self.data[index] = value
# del l[index]
def __delitem__(self, index):
if index in self.data:
del self.data[index]
# value in l
def __contains__(self, value):
return value == 0.0 or value in self.data.values()
# len(l)
def __len__(self):
return self.size
# for value in l: ...
def __iter__(self):
return (self[i] for i in range(self.size)) # use xrange for python2
次に、通常のlist
ようなsparselist
list
使用することができます。
l = sparselist(10 ** 6) # list with 1 million elements
0 in l # True
10 in l # False
l[12345] = 10
10 in l # True
l[12345] # 10
for v in l:
pass # 0, 0, 0, ... 10, 0, 0 ... 0
呼び出し可能な型
class adder(object):
def __init__(self, first):
self.first = first
# a(...)
def __call__(self, second):
return self.first + second
add2 = adder(2)
add2(1) # 3
add2(2) # 4
実装されていない動作の処理
あなたのクラスが提供する引数の型のための特定のオーバーロードされた演算子を実装していない場合、それはすべきreturn NotImplemented
(これがあることに注意して、特別な定数と同じではない、 NotImplementedError
)。これにより、Pythonは他のメソッドを試して操作を行うことができます:
NotImplemented
が返されると、インタプリタは、演算子に応じて、他の型または他のフォールバックに対して、反映された操作を試行します。試行された操作のすべてがNotImplemented
返した場合、インタプリタは適切な例外を発生させます。
たとえば、 x + y
と、 x.__add__(y)
が実装されていない場合、 y.__radd__(x)
が代わりに実行されます。
class NotAddable(object):
def __init__(self, value):
self.value = value
def __add__(self, other):
return NotImplemented
class Addable(NotAddable):
def __add__(self, other):
return Addable(self.value + other.value)
__radd__ = __add__
これが反映されたメソッドであるため、すべてのケースで期待される動作を得るために__add__
と __radd__
を実装する__add__
あります。幸運にも、この単純な例では両方とも同じことをしているので、私たちは簡単なことをすることができます。
使用中で:
>>> x = NotAddable(1)
>>> y = Addable(2)
>>> x + x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NotAddable' and 'NotAddable'
>>> y + y
<so.Addable object at 0x1095974d0>
>>> z = x + y
>>> z
<so.Addable object at 0x109597510>
>>> z.value
3
オペレータのオーバーロード
以下は、クラス内でオーバーロードできる演算子と必要なメソッド定義、式内で使用されている演算子の例です。
注意変数名としてのother
の使用は必須ではありませんが、標準と見なされます。
オペレーター | 方法 | 式 |
---|---|---|
+ 加算 | __add__(self, other) | a1 + a2 |
- 減算 | __sub__(self, other) | a1 - a2 |
* 乗算 | __mul__(self, other) | a1 * a2 |
@ 行列の乗算 | __matmul__(self, other) | a1 @ a2 ( Python 3.5 ) |
/ 部門 | __div__(self, other) | a1 / a2 ( Python 2のみ ) |
/ 部門 | __truediv__(self, other) | a1 / a2 ( Python 3 ) |
// フロアディビジョン | __floordiv__(self, other) | a1 // a2 |
% モジュロ/余り | __mod__(self, other) | a1 % a2 |
** パワー | __pow__(self, other[, modulo]) | a1 ** a2 |
<< ビットごとの左シフト | __lshift__(self, other) | a1 << a2 |
>> ビット単位の右シフト | __rshift__(self, other) | a1 >> a2 |
& ビットAND | __and__(self, other) | a1 & a2 |
^ ビット単位の排他的論理和 | __xor__(self, other) | a1 ^ a2 |
| (ビットOR) | __or__(self, other) | a1 | a2 |
- 否定(算術) | __neg__(self) | -a1 |
+ 正 | __pos__(self) | +a1 |
~ ビット単位のNOT | __invert__(self) | ~a1 |
< より小さい | __lt__(self, other) | a1 < a2 |
<= より小さいか等しい | __le__(self, other) | a1 <= a2 |
== 等しい | __eq__(self, other) | a1 == a2 |
!= 等しくない | __ne__(self, other) | a1 != a2 |
> より大きい | __gt__(self, other) | a1 > a2 |
>= より大きいまたは等しい | __ge__(self, other) | a1 >= a2 |
[index] 索引演算子 | __getitem__(self, index) | a1[index] |
in には演算子 | __contains__(self, other) | a2 in a1 |
(*args, ...) 呼び出し | __call__(self, *args, **kwargs) | a1(*args, **kwargs) |
__pow__
modulo
オプションのパラメータは、 pow
組み込み関数でのみ使用されます。
バイナリ演算子に対応する各メソッドには、対応する__r
で始まる__r
などの「正しい」メソッドがあり__radd__
。
class A:
def __init__(self, a):
self.a = a
def __add__(self, other):
return self.a + other
def __radd__(self, other):
print("radd")
return other + self.a
A(1) + 2 # Out: 3
2 + A(1) # prints radd. Out: 3
対応する__i
バージョンと同様に、 __i
で始まり__i
。
class B:
def __init__(self, b):
self.b = b
def __iadd__(self, other):
self.b += other
print("iadd")
return self
b = B(2)
b.b # Out: 2
b += 1 # prints iadd
b.b # Out: 3
これらのメソッドには特別なものはないので、言語の他の多くの部分、標準ライブラリの部分、さらにはサードパーティのモジュールでさえ、オブジェクトを型にキャストするメソッドやオブジェクトのプロパティをチェックするメソッドのような独自のメソッドを追加します。たとえば、組み込みのstr()
関数は、オブジェクトの__str__
メソッドが存在する場合にそれを呼び出します。これらの用途の一部を以下に示します。
関数 | 方法 | 式 |
---|---|---|
int キャスト | __int__(self) | int(a1) |
絶対関数 | __abs__(self) | abs(a1) |
str キャストする | __str__(self) | str(a1) |
unicode へのキャスト | __unicode__(self) | unicode(a1) (Python 2のみ) |
文字列表現 | __repr__(self) | repr(a1) |
bool へのキャスティング | __nonzero__(self) | bool(a1) |
文字列の書式設定 | __format__(self, formatstr) | "Hi {:abc}".format(a1) |
ハッシング | __hash__(self) | hash(a1) |
長さ | __len__(self) | len(a1) |
逆転 | __reversed__(self) | reversed(a1) |
床 | __floor__(self) | math.floor(a1) |
天井 | __ceil__(self) | math.ceil(a1) |
コンテキストマネージャには__enter__
や__exit__
特別なメソッドもあります。