誰かがこれに対するマクロベースの解決策を私に求めたので、ここにあります:
# macropy/my_macro.py
from macropy.core.macros import *
macros = Macros()
@macros.decorator()
def recursive(tree, **kw):
tree.decorator_list = []
wrapper = FunctionDef(
name=tree.name,
args=tree.args,
body=[],
decorator_list=tree.decorator_list
)
return_call = Return(
Call(
func = Name(id=tree.name),
args = tree.args.args,
keywords = [],
starargs = tree.args.vararg,
kwargs = tree.args.kwarg
)
)
return_call = parse_stmt(unparse_ast(return_call))[0]
wrapper.body = [tree, return_call]
return wrapper
これは次のように使用できます。
>>> import macropy.core.console
0=[]=====> MacroPy Enabled <=====[]=0
>>> from macropy.my_macro import macros, recursive
>>> @recursive
... def fib(n):
... return n if n <= 1 else fib(n-1)+fib(n-2)
...
>>> foo = fib
>>> fib = foo(10)
>>> x = foo(8)
>>> x
21
それは基本的に hus787 が与えたラッピングを正確に行います:
return fib(...)
元の関数の引数リストを...
def
古いものと同じ名前、同じ引数、同じ decorator_list で新しい を作成します
- 新しい functiondef の本体に、古い関数を配置し、その後に
return
ステートメントを続けます。
- デコレーターの元の機能を取り除きます (代わりにラッパーをデコレートしたいと思います)
ごみは、何かを機能させるための簡単なハックです(実際には、関数のパラメーターリストからASTをparse_stmt(unparse_ast(return_call))[0]
コピーしてASTで使用することはできません)が、それは単なる詳細です。argument
Call
実際にそれを行っていることを示すために、print unparse_ast
ステートメントを追加して、変換された関数がどのように見えるかを確認できます。
@macros.decorator()
def recursive(tree, **kw):
...
print unparse_ast(wrapper)
return wrapper
上記のように実行すると、印刷されます
def fib(n):
def fib(n):
return (n if (n <= 1) else (fib((n - 1)) + fib((n - 2))))
return fib(n)
まさにあなたが望むもののように見えます! 複数の引数、kwargs、デフォルトなどを使用して、どの関数でも機能するはずですが、テストするのが面倒です。AST での作業は少し冗長で、MacroPyはまだ非常に実験的なものですが、かなりうまくできていると思います。