Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Pythonのクラスのインスタンスメソッドを動的に追加する

More than 1 year has passed since last update.

ある抽象クラスの継承先で、メンバ変数のリスト内の文字列に応じてインスタンスメソッドを作るという設計をしました。
新規追加メソッド作成のロジック自体は自明なので、文字列の数分いちいちメソッドを書き下すのは冗長だし時間がかかる。
そこで外からインスタンスメソッドを代入するという方法を思いついた。
その思考錯誤が結構面白かった。

失敗例


# ある変数のゲッターを作る
def make_getter(variable_name):
    def f(self):
        return getattr(self, variable_name)

    return f

class Parent(object):
    def __init__(self, variable_list):
        # ゲッターを代入する
        for variable in variable_list:
            setattr(self, 'get_'+variable, make_getter(variable))


class Child(Parent):

    def __init__(self):
        variable_list = ['hoge', 'fuga', 'piyo']
        super().__init__(variable_list)

まず上記の例だと、Childのインスタンスではchild.get_hoge()を呼ぶと素っ頓狂なエラーが返ってくる。
TypeError: f() missing 1 required positional argument: 'self'

なにをいってるんだ。Pythonのインスタンスメソッドの第一引数には暗黙的に自身が指定されるはずだろう。
と思うものの、素っ頓狂なことをしているのはPythonのインタプリタではなくてやっぱり自分でした。

インスタンスメソッドとして認識されるのは、インスタンスの持つ関数ではなくて、その型であるクラスに登録された関数のみ。
イニシャライズの途中にselfに関数を代入したからといって、インスタンスメソッドにならないということですね。いわゆるstaticmethodを追加するならこのやり方でよいということになります。

成功例

このため、下記ケースではchild.get_hoge()を想定通り実行することができる。


# ある変数のゲッターを作る
def make_getter(variable_name):
    def f(self):
        return getattr(self, variable_name)

    return f

class Parent(object):
    def __init__(self, variable_list):
        # ゲッターを代入する
        for variable in variable_list:
            setattr(self.__class__, 'get_'+variable, make_getter(variable))


class Child(Parent):

    def __init__(self):
        variable_list = ['hoge', 'fuga', 'piyo']
        super().__init__(variable_list)

インスタンス化最中のselfオブジェクトの型クラスにsetattrして改造するということをしています。
まあ邪道実装極まりないのですが、また一つPythonに詳しくなれたのでよかったです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away