arguments.callee
なんかarguments.calleeとかいうものが流行っているらしい。
- Perl で JS の arguments.callee 的なことしようと思ってハマった - IT戦記
- はじめての coderepos で arguments::callee 初体験 - TAKESAKOのはてな出張所
- それDevel::Caller でできるよ - TokuLog 改め だまってコードを書けよハゲ
- 404 Blog Not Found:perl - で(Recall()|arguments.callee()|&?BLOCK())
なので作ってみました。
@enable_arguments_callee def foo(): print arguments.callee foo() #=> <function foo at 0x014916F0> @enable_arguments_callee def facto(n): if n == 1: return 1 return n * arguments.callee(n - 1) print facto(5) #=> 120 print repr(arguments.callee) #=> None
こんな感じの挙動をすればいいんでしょうか。
実装は下のような感じ。デコレータを使って、関数呼び出しの前後に「その関数をargumentsオブジェクトの持っているスタックにプッシュする」「ポップする」という処理を付け加えています。デコレータというのは引数に関数を取って関数を返す関数です。あとargumentsオブジェクトはビルトイン名前空間に入れてどこからでも「arguments」という名前で呼び出せるようにしました。
import __builtin__ class Arguments(object): value = [None] def push(self, f): self.value.append(f) self.callee = f def pop(self): self.value.pop() self.callee = self.value[-1] __builtin__.arguments = Arguments() del Arguments def enable_arguments_callee(f): def wrap(*args, **kw): arguments.push(f) result = f(*args, **kw) arguments.pop() return result return wrap
問い:この実装の問題点は何でしょう。
とりあえずarguments.calleeに関する処理はあくまでenable_arguments_calleeデコレータの中で行っているので、たとえばenableした関数Aからしていない関数Bを呼んでその中でarguments.calleeを参照した場合その値は関数Aです。あと関数にはいるのは関数の呼び出し時のみだという仮定を置いているのでスレッドを使ったりすると壊れます。