提问人:Toothpick Anemone 提问时间:9/18/2022 更新时间:9/19/2022 访问量:192
什么装饰器将允许我们调用一个函数,其中每个单独的参数都用括号括起来?
What decorator will allow us to call a function where each individual argument is wrapped in parentheses?
问:
我们从函数开始,如下所示:
def funky_function(x1, x2, x3, x4, /):
return ", ".join(" ".join(str(x).split()) for x in [x1, x2, x3, x4])
修饰函数后,我们应该在每个调用参数周围写括号。
r = f(1)(2)(3)(4) # GOOD
# r = f(1, 2, 3, 4) # BAD
一个潜在的应用是泛化装饰器。
某些装饰器只处理单参数函数。
我们可能需要一个新的装饰器,它适用于多参数函数。
例如,您可以通过泛化 来实现函数重载(多重调度)。其他人已经实施了多种方法;所以这不是我的问题。但是,我想提供一些示例应用程序作为动力。functools.singledispatch
from functools import singledispatch
@singledispatch
def fun(arg):
pass
@fun.register
def _(arg: int):
print("I am processing an integer")
@fun.register
def _(arg: list):
print("I am processing a list")
我尝试编写一些代码来完成此任务,但它没有表现出所需的行为。理想情况下,修饰函数会变成一个参数的函数,该参数返回另一个函数。
return_value = f(1)(2)(3)(4)
下面是一些代码:
from functools import *
from inspect import *
class SeperatorHelper:
def __init__(self, func):
"""`func` should be callable"""
assert(callable(func))
self._func = func
def __call__(self, arg):
return type(self)(partial(self._func, arg))
def seperate_args(old_func, /):
"""
This is a decorator
@seperate_args
def foo(x1, x2, x3, x4, /):
pass
+------------------+------------------+
| NEW | OLD |
+------------------+------------------+
| f(1)(2)(3)(4) | f(1, 2, 3, 4) |
+------------------+------------------+
"""
new_func = SeperatorHelper(old_func)
new_func = wraps(old_func)(new_func)
return new_func
#######################################################
# BEGIN TESTING
#######################################################
@seperate_args
def funky_function(x1, x2, x3, x4, /):
return ", ".join(" ".join(str(x).split()) for x in [x1, x2, x3, x4])
print("signature == ", signature(funky_function))
func_calls = [
"funky_function(1)(2)",
"funky_function(1)(2)(3)(4)",
"funky_function(1)(2)(3)(4)("extra arg")",
"funky_function(1)(2)(3)(4)()()()()"
]
for func_call in func_calls:
try:
ret_val = eval(func_call)
except BaseException as exc:
ret_val = exc
# convert `ret_val` into a string
# and eliminate line-feeds, tabs, carriage-returns...
ret_val = " ".join(str(ret_val).split())
print(40*"-")
print(func_call)
print("return value".ljust(40), )
print(40 * "-")
答:
0赞
Charles Duffy
9/19/2022
#1
作为一个不试图全面处理极端情况的快速尝试——
from inspect import signature
from functools import partial
def curry(orig_func):
sig = signature(orig_func)
target_arg_count = len(sig.parameters)
args=[]
new_func = orig_func
for n in range(len(sig.parameters)):
def curry_step(*args):
if len(args) < target_arg_count:
return partial(new_func, *args)
return orig_func(*args)
new_func = curry_step
return new_func
@curry
def funky_function(x1, x2, x3, x4, /):
return ", ".join(" ".join(str(x).split()) for x in [x1, x2, x3, x4])
评论
eval
functools.partial
;使用它将使您的工作更轻松。:)