Python.use(better, follow=”K&R”) リファクタリング 8/10

Previous|8/10|Next

Python.use(better, follow=”K&R”) # for novice 記事一覧

改訂♪2008/10/04

[Python]特殊メソッド __setitem__

演算子 [] と = を組み合わせたときの動作を規定するのが、特殊メソッド __setitem__ です。それは、次のようにして確認できます。


>>> class Reverse: pass

>>> dir(Reverse)
['__doc__', '__module__']

新たに定義したクラス Reverse には、まだメソッドを定義していません。そのため、


>>> Reverse()[0] = 1

Traceback (most recent call last):
File "", line 1, in
Reverse()[0] = 1
AttributeError: Reverse instance has no attribute '__setitem__'

新たに生成した Reverse インスタンスに、演算子 を適用すると、例外 AttributeError を生成して、エラーメッセージを出力します。これを見ると、演算子 に呼応する __setitem__ が必要になることが分かります。
そこで、演算子 [] を任意のインスタンスに適用できるように、__setitem__ を再定義します。

[Python]組み込み型の操作


>>> help(dict.__setitem__) # 特殊メソッド
Help on wrapper_descriptor:

__setitem__(...)
x.__setitem__(i, y) <==> x[i]=y

任意のインスタンス s に対して、式 s[key]=value を評価するときに、このメソッドを呼び出します。つまり、式 s. __setitem__(key,value) と等価です。dict に対しては、key が見つからないと、value を値とする、新たな要素対(key/value)を追加します。

便宜的な事例

クラス Reverse は(説明用の便宜的なもので)与えられた文字列の順序を入れ換え(反転し)て、新たな文字列を生成するだけのものです。


class Reverse:
def __init__(self, s):
self.s = s[::-1]
def __setitem__(self, key, value):
self.s = self[:key]+value+self[key+1:]

メソッド __setitem__ は、演算子 と = を利用して、インスタンス属性 self.s が保持する文字列の一部を置き換えた、新たな文字列を生成します。ここで興味深いのは、演算子 の動作を規定するメソッド __setitem__ を実現するときに、他の を利用していることです。つまり、演算子 を Reverse インスタンスに適用すると、それは演算子 [] を文字列 self.s に適用することに帰着します。


>>> s = Reverse("ABC")
>>> print s
CBA
>>> s[1] = "x"
>>> print s
CxA

反転した文字列 s を生成して、その添字式を伴う s[1]="X" を実行すると、その一部を置換した新たな文字列が得られます。文字列は、変更不能オブジェクトなので、新たな文字列を生成する必要があります。

[Python]実用的な事例

組み込み型 dict の中から任意のキーに対応する値を設定するのに、演算子 [] と = を組み合わせて利用できます。クラス eXdict の傘下でも、これに準拠します。


class eXdict:
def __setitem__(self, key, value):
raise NotImplementedError

class HashTable(eXdict):
def __setitem__(self, key, value):
e = self._detect(key)
if e:
e[key] = value
else:
k = self.hash(key)
self.hashtab[k] = self.hashtab[k].entry(key, value)

class BinTree(eXdict):
...
class Tnode(BinTree):
def __setitem__(self, key, value):
node = self.add(key)
node = node._detect(key)
if node: node.count = value

抽象クラス eXdict では、メソッド __setitem__ が例外 NotImplementedError を生成します。これは、子孫クラスにおいて、このメソッドを再定義する必要があることを意味します。


Previous|8/10|Next