什么样的装饰器允许我们调用一个函数,其中每个单独的参数都用括号括起来



我们从一个函数开始,例如:

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

一个潜在的应用程序是泛化装饰器
有些装饰器只处理单参数函数。

我们可能想要一个新的decorator,它可以处理多参数函数。

例如,您可以通过泛化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 * "-")

作为一种不尝试全面处理角落案例的快速尝试——

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])

最新更新