0
0

関数の代わりにインスタンスメソッドをコールバックさせる

Last updated at Posted at 2024-01-19

pythonの小ネタです。

概要

  • 引数にコールバック関数を渡す代わりにインスタンスメソッドを渡すと、そのままコールバックされるし、selfも参照できる。

情報量はこの一文で全てです。あまりやる機会もなさそうですが、「やったらどうなるのかな」と思う方がいるかもしれないので試して書きます。

関数に関数を渡す

関数Aの引数として関数Bを渡して、関数Aの中から関数Bを呼ぶ。いわゆるコールバックですね。標準ライブラリでも沢山使われているのでお馴染みだと思います。

funcparam.py
def func_caller(func):
    """関数を受け取って呼び出す関数"""
    func('引数を渡します。')

def param_func(text):
    """func_callerから呼び出される関数"""
    print(text)

# 関数に関数を引数で渡す 
func_caller(param_func)

実行結果も何の変哲もない。

$ python funcparam.py
引数を渡します。

printする関数param_funcfunc_callerから呼び出すだけなので普通にprintされます。

関数にインスタンスのメソッドだけ渡す

今度はクラスのインスタンスの中からメソッド部分だけをコールバック関数の代わりに渡します。引数にインスタンスが含まれないのでメソッドのselfがどうなるのかちょっと見た感じでは気になる書き方です。

methodparam.py
def func_caller(func):
    """関数を受け取って呼び出す関数(さっきと同じ)"""
    func('引数を渡します。')

class ParamClass:
    """引数にするメソッドを持つクラス"""
    
    def __init__(self, mytext) -> None:
        """インスタンス変数mytextを持つ"""
        self.mytext = mytext

    def param_method(self, text):
        """引数textとself.mytextを一緒に出力する"""
        print(text, self.mytext)

# インスタンスを生成して、メソッドを引数にする
param_class = ParamClass('インスタンス変数も使えます。')
func_caller(param_class.param_method)

実行結果はこうなります。

$ python methodparam.py
引数を渡します。 インスタンス変数も使えます。

instance.method()のような呼び出しと変わらずselfが渡されので、いつも通りに自由な操作が行えます。しかし、これを使ってコールバック内からselfを操作してインスタンスの状態を変更するのは混乱を招くのでやめたほうがいいでしょう。せめてselfの内容を参照する程度にとどめておくべきでしょう。1
少なくともpythonの標準ライブラリ内ではこんな使い方をしたいライブラリはほとんどなさそうに思えます。強いて言うなら、コールバック関数が何らかのファクトリとして動作するときにはちょっと検討してもいいかもしれません。2

  1. そもそもselfを参照したいならコールバックよりもインスタンスを受け取った方が素直だと思います。最初からコールバック関数を受け取る仕様になっている汎用的な関数に対してインスタンスの情報を与えるための強引なトリックとしては使えなくもない?

  2. 例えばDB-APIで使うrow_factoryjson.dumpに渡すdefaultなどはコールバック経由でselfの中身を参照することで柔軟な動作を期待できるかもしれない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0