リストっぽい何か
__getitem__と__setitem__を定義すると、リストみたいに[]を使って要素を参照したり代入したりできます。
class Foo: def __init__(self, filename): self.file = file(filename, 'r+') def __setitem__(self, index, value): self.file.seek(index) self.file.write(value) def __getitem__(self, index): self.file.seek(index) return self.file.read(1) f = Foo('list.txt') a = 'apple' for i in range(len(a)): f[i] = a[i] for i in range(len(a)): print f[i]
実行結果は以下のようになります。
a p p l e
最後のforループがかっこ悪いので改良してみました。
class Foo: def __init__(self, filename): self.file = file(filename, 'r+') self.len = 0 def __setitem__(self, index, value): self.len += 1 self.file.seek(index) self.file.write(value) def __getitem__(self, index): self.file.seek(index) return self.file.read(1) def __len__(self): return self.len def __iter__(self): self.i = 0 return self def next(self): if self.i == self.len: raise StopIteration else: r = self[self.i] self.i += 1 return r f = Foo('list.txt') a = 'apple' for i in range(len(a)): f[i] = a[i] # かっこ悪いオリジナル for i in range(len(a)): print f[i] # __len__が定義されているのでlenが使える for i in range(len(f)): print f[i] # イテレータを返すのでforにそのまま渡せる for i in f: print i
比較
インスタンスの比較をしてみます。
class Foo: def __init__(self, name): self.name = name self.len = len(name) def __lt__(self, other): return self.len < other.len def __le__(self, other): return self.len <= other.len def __eq__(self, other): return self.name == other.name def __ne__(self, other): return self.name != other.name def __gt__(self, other): return self.len > other.len def __ge__(self, other): return self.len >= other.len a = Foo('work') b = Foo('lover') print a < b, a.__lt__(b) # => True True print a <= b, a.__le__(b) # => True True print a == b, a.__eq__(b) # => False False print a != b, a.__ne__(b) # => True True print a > b, a.__gt__(b) # => False False print a >= b, a.__ge__(b) # => False False
比較演算を行うと、比較演算子に対応したメソッドが呼ばれます。これらが定義されていない場合、__cmp__を見にいきます。__cmp__を定義するときは、自分が相手より小さい場合は負の値を、同じ場合は0を、自分が相手より大きい場合は正の値を返すようにする、という決まりがあります。
class Foo: def __init__(self, name): self.name = name self.len = len(name) def __cmp__(self, other): if self.len < other.len: return -1 elif self.len > other.len: return 1 else: return 0 a = Foo('work') b = Foo('lover') print a < b # => True print a <= b # => True print a == b # => False print a != b # => True print a > b # => False print a >= b # => False print a.__cmp__(b) # => -1 a = Foo('orange') b = Foo('banana') print a < b # => False print a <= b # => True print a == b # => True print a != b # => False print a > b # => False print a >= b # => True print a.__cmp__(b) # => 0
比較演算子が__cmp__を呼び出したときは、結果に応じて勝手にTrueとFalseにしてくれるみたいです。
__cmp__も定義されていない場合はインスタンスのアドレスにより比較が行われます。
class Foo: def __init__(self, name): self.name = name self.len = len(name) a = Foo('work') b = Foo('lover') print a < b # => False print a <= b # => False print a == b # => False print a != b # => True print a > b # => True print a >= b # => True print id(a), id(b) # => -1211313844 -1211313940