「
python recurse itself without name」や「
python arguments.callee」でググったら以下のページを見つけた。
なんか、
decorator の @wrapper 構文使うと関数 wrap 出来るらしくて、第一パラメータに self 入れといてそこに arguments.callee 相当の値(つまり、当該の関数自身)を渡すような細工を出来るっぽい。
その際、
functools.wraps を使うのが定番な模様。
とりあえず、以下の関数定義してデコレータとして使うと、第1引数が callee 扱いになる。
# @reference https://stackoverflow.com/a/35951133
from functools import wraps
def recfun(f):
@wraps(f)
def _f(*a, **k): return f(_f, *a, **k)
return _f
import inspect
@recfun
def factorial(self, n):
'''Calculate n!.'''
if not isinstance(n, int): raise ValueError(f"{inspect.currentframe().f_code.co_name}() only accepts integral values")
if n < 0: raise ValueError(f"{inspect.currentframe().f_code.co_name}() not defined for negative values")
return 1 if n < 1 else self(n-1) * n;
とりあえず、これが正解っぽい。
2022-06-23: 追記
これ、よく考えたら inspect も不要だった。
@recfun
def factorial(self, n):
'''Calculate n!.'''
if not isinstance(n, int): raise ValueError(f"{self.__name__}() only accepts integral values")
if n < 0: raise ValueError(f"{self.__name__}() not defined for negative values")
return 1 if n < 1 else self(n-1) * n;
おぉ、凄い書き易いぞ!
ただ、これ wrap されるので、呼び出し時に微妙にオーバーヘッドかかるのが嫌ってのはあるかもしれないけど
/2022-06-23: 追記
inspect.currentframe().f_code.co_name を eval() して
callee = eval(inspect.currentframe().f_code.co_name)
みたいにする方法もあるみたいだが、再帰の度に評価されるの辛い。
デフォルト引数に
def factorial(n, _callee = factorial):
'''Calculate n!.'''
if not isinstance(n, int): raise ValueError(f"{_callee.__name__}() only accepts integral values")
if n < 0: raise ValueError(f"{_callee.__name__}() not defined for negative values")
return 1 if n < 1 else _callee(n-1) * n;
ってするのは、2か所書き換え必要なのでちょっと面倒だけど、書き換える箇所は近くなるので悪くないのでは?
と思ったが、def factorial() で関数する時点ではまだ factorial が定義されてないので参照できなかった。
じゃ、関数内で最初に代入すればと思ったが
def factorial(n):
'''Calculate n!.'''
callee = factorial
if not isinstance(n, int): raise ValueError(f"{callee.__name__}() only accepts integral values")
if n < 0: raise ValueError(f"{callee.__name__}() not defined for negative values")
return 1 if n < 1 else callee(n-1) * n;
みたいになるので、docstring が長いと、書き換え必要な個所が遠くなってしまうので嬉しくない感じ。