読者です 読者をやめる 読者になる 読者になる

何かを書き留める何か

数学や読んだ本について書く何かです。最近は社会人として生き残りの術を学ぶ日々です。

『Effective Python』Item 24: ジェネリックなオブジェクト構築には@classmethodポリモーフィズムを使おう

Effective Python Python

『Effective Python』の続き。__init__ポリモーフィズムwww.effectivepython.com

Googleに勤務する筆者らしく、MapReduceの構築を例にジェネリックなオブジェクト構築を説明している。 ハードディスク上の巨大なファイルの行数を数え上げる機能を実装しているが、拡張しやすいようにジェネリックに書きたいよね、という流れ。

Pythonのクラスのコンストラクタ__init__しかないので、@classmethodデコレータでジェネリックなオブジェクト構築を実現しようという流れ。

class GenericInputData(object):
    def read(self):
        raise NotImplementedError

    @classmethod
    def generate_inputs(cls, config):
        raise NotImplementedError


class PathInputData(GenericInputData):
    def __init__(self, path):
        super().__init__()
        self.path = path

    def read(self):
        return open(self.path).read()

    @classmethod
    def generate_inputs(cls, config):
        data_dir = config['data_dir']
        for name in os.listdir(data_dir):
            yield cls(os.path.join(data_dir, name))

@classmethodでデコレートされたgenerate_inputs内で__init__を実行している。 ちょっとわかりずらいが、generate_inputsはクラスメソッドであるので第一引数にクラスそのものclsが渡され、cls()として__init__を実行している。

こちらはMapReduceにおけるWorkerの実装。

class GenericWorker(object):
    def __init__(self, input_data):
        self.input_data = input_data
        self.result = None

    def map(self):
        raise NotImplementedError

    def reduce(self, other):
        raise NotImplementedError

    @classmethod
    def create_workers(cls, input_class, config):
        workers = []
        for input_data in input_class.generate_inputs(config):
            workers.append(cls(input_data))
        return workers


class LineCountWorker(GenericWorker):
    def map(self):
        data = self.input_data.read()
        self.result = data.count('\n')

    def reduce(self, other):
        self.result += other.result

create_workers内でinput_class.generate_inputsを利用している。また、workers.append(cls(input_data))として内部で__init__を実行している。

恥ずかしながら、Pythonで大規模なプログラムを構築したことが無く、このありがたみがよくわかっていないが、サブクラスがどんな形をしていても同じように実行できるという点はよいことである。 また、この項目を読んだ際にTypoレベルの誤りを発見し、筆者に報告したところ取り上げてくれた。

Item 24, p. 69, L13: classes vs subclasses · Issue #25 · bslatkin/effectivepython · GitHub

それにしても、もう少しちゃんとした英文が書けるようになりたいものである。