🐍

curve_fitみたいに引数の数を判定して呼べるようにする

2024/06/01に公開

Scypiにscipy.optimize.curve_fitという関数がありますね。この関数はフィッティングしたい関数とx,yのデータを渡してあげると定数を調整して渡した関数にフィッティングしてくれるのですが、なんと関数を渡すだけで引数の個数(ここでは定数の個数)を自動で判定してくれます。このようなプログラムの実装方法を調べてみました。

引数の個数を知る方法

まずは引数の個数を知る方法からです。inspectモジュールを使います。

import inspect
def foo(a: int, b):
    pass
sig = inspect.signature(foo)
for arg in sig.parameters.values():
    print(arg.name, arg.annotation)
a <class 'int'>
b <class 'inspect._empty'>

このようにすることで、仮引数名とアノテーションが取得できます。
https://docs.python.org/ja/3/library/inspect.html

引数の個数を動的に変える方法

引数の個数を知れても実際に値を渡せなければ意味がありません。実際に値を渡すには以下のようにします。

def foo(a: int, b):
    pass
foo(*[1, 1.1])
foo(**{'b': 1.1, 'a': 1})

上記のような方法で、リストや辞書をアンパックして渡すことができます。
https://qiita.com/LouiS0616/items/1bbe0a9bb93054f6c380

まとめ

inspectモジュールと***を使うことでcurve_fitのような関数が実装できました。最後にアノテーションを見ながら引数の数に合わせて関数を呼び出すプログラムをおいておきます。

import inspect

def foo():
    print('foo')

def bar(a: int, b, c: float, d: int):
    print('bar', a, b, c, d)

def caller(func):
    sig = inspect.signature(func)
    v = []
    for arg in sig.parameters.values():
        if arg.annotation == int:
            v.append(0)
        elif arg.annotation == float:
            v.append(0.0)
        else:
            v.append('Hello')
    func(*v)

caller(foo)
caller(bar)
foo
bar 0 Hello 0.0 0

Discussion