Python.use(better, follow=”K&R”) リファクタリング 8/10
Python.use(better, follow=”K&R”) # for novice 《記事一覧》
[Python]特殊メソッド __setitem__
演算子 [] と = を組み合わせたときの動作を規定するのが、特殊メソッド __setitem__ です。それは、次のようにして確認できます。
>>> class Reverse: pass>>> dir(Reverse)
['__doc__', '__module__']
新たに定義したクラス Reverse には、まだメソッドを定義していません。そのため、
>>> Reverse()[0] = 1Traceback (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 を生成します。これは、子孫クラスにおいて、このメソッドを再定義する必要があることを意味します。