自動委譲と__getattr__

Decoratorパターンの項でも書きましたが、「メンバのメソッドに丸投げするメソッド」をしばしば書く必要が出てきます。

class WriterDecorator(object):
    #以下のメソッドは単にwriterに丸投げ
    def writeline(self, line):
        return self.writer.writeline(line)

の様に。そこで、こういうのを自動的に行うようにします。
やり方は数種類あるようです。

方法1:__init__で属性をセット

一番分かりやすい方法です。getattr(self.writer, name)で、self.writerのbound methodを取れるのを利用します。

class SimpleWriter(object):
    def __init__(self, path):
        self.file = open(path, "w")
    
    def writeline(self, line):
        print >> self.file, line
    
    def pos(self):
        return self.file.tell()
    
    def rewind(self):
        self.file.seek(0) 
    
    def close(self):
        self.file.close()

class WriterDecorator1(object):
    deligates = "writeline pos rewind close".split()
    def __init__(self, writer):
        self.writer = writer
        
        for method_name in self.deligates:
            method = getattr(self.writer, name)
            setattr(self, name, method)

方法2:__getattr__

w.spam のように、属性を取り出そうとしたが、
wがspamという属性を持っていなかったとき、__getattr__が呼ばれるので、
__getattr__の中で、委譲相手のメソッドを取って来ます。

委譲したいメソッドの数が多く、書き並べるのが面倒な場合に便利な方法です。
もちろん、指定したメソッドだけ委譲することも出来ます。

class WriterDecorator2(object):
    def __init__(self, writer):
        self.writer = writer
    
    def __getattr__(self, name):
        #自分に無い属性はてself.writerからとって来る
        return getattr(self.writer, name)
    
    ##def __getattr__(self, name):
    ##    #指定した属性だけself.writerからとって来る
    ##    deligates = "writeline pos rewind close".split()
    ##    if name in deligates:
    ##        return getattr(self.writer, name)
    ##    else:
    ##        return object.__getattr__(self, name)

ちょっと黒い自動委譲
に続きます。