如何取消 Python 中的函数?
How do I uncurry a function in Python?
最近学习了'Programming language' using standard ML,并且学习了柯里化方法(或其他东西),所以我在Python中应用了它。
下面是简单的函数和柯里化。
def range_new(x, y):
return [i for i in range(x, y+1)]
def curry_2(f):
return lambda x: lambda y: f(x, y)
def uncurry_2(f):
pass # I don't know it...
print(range_new(1, 10))
curried_range = curry_2(range_new)
countup = curried_range(1)
print(countup(10))
print(curried_range(1)(10))
结果如下。而且效果很好;使用 curry_2
我们可以创建一个新函数 (countup
)。但是,然后我想制作一个非咖喱函数。
但是,我不知道该怎么做。
我该怎么做?
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
最简单的解决方案是用取消柯里化的代码再次包装柯里化函数:
def uncurry_2(f):
return lambda x, y: f(x)(y)
uncurried_range = uncurry_2(curried_range)
print(uncurried_range(1, 10))
这不是很好的风格,但您可以使用返回的 lambda
:
的(可能 CPython-only)__closure__
属性访问闭包中的变量
>>> countup.__closure__[0].cell_contents
<function __main__.range_new>
这会访问您函数 curry_2
最内层闭包的内容(最内层 lambda
使用的变量),因此 returns 您在那里使用的函数。
但是在生产代码中你不应该使用它。最好为柯里化创建一个 class(或函数),它支持访问未柯里化的函数(lambda
没有提供)。但是 Python 中的一些函数工具支持访问 "decorated" 函数,例如 partial
:
>>> from functools import partial
>>> countup = partial(range_new, 1)
>>> print(countup(10))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> countup.func
<function __main__.range_new>
我相信 uncurry 是指您想让函数接受更多参数。您是否考虑过使用 "partial" 函数?它允许您在调用方法时使用任意数量的参数。
from functools import partial
def f(a, b, c, d):
print(a, b, c, d)
g = partial(partial(f, 1, 2), 3)
g(4)
实施它应该非常简单
def partial(fn, *args):
def new_func(*args2):
newArgs = args + args2
fn(*newArgs)
return new_func;
请注意原始问题中提供的代码,上面的代码称为部分应用程序。 Currying 通常比这更灵活——这里是你如何使用 Python 3 来做到这一点(它在 Python 2 中更棘手)。
def curry(fn, *args1):
current_args = args1
sig = signature(fn)
def new_fn(*args2):
nonlocal current_args
current_args += args2
if len(sig.parameters) > len(current_args):
return new_fn
else:
return fn(*current_args)
return new_fn
j = curry(f)
j(1)(2, 3)(4)
现在回到您的代码。 range_new 现在可以通过几种新方式使用:
print(range_new(1, 10))
curried_range = curry(range_new)
countup = curried_range(1)
print(countup(10))
countup_again = curried_range
print(countup_again(1, 10))
最近学习了'Programming language' using standard ML,并且学习了柯里化方法(或其他东西),所以我在Python中应用了它。 下面是简单的函数和柯里化。
def range_new(x, y):
return [i for i in range(x, y+1)]
def curry_2(f):
return lambda x: lambda y: f(x, y)
def uncurry_2(f):
pass # I don't know it...
print(range_new(1, 10))
curried_range = curry_2(range_new)
countup = curried_range(1)
print(countup(10))
print(curried_range(1)(10))
结果如下。而且效果很好;使用 curry_2
我们可以创建一个新函数 (countup
)。但是,然后我想制作一个非咖喱函数。
但是,我不知道该怎么做。
我该怎么做?
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
最简单的解决方案是用取消柯里化的代码再次包装柯里化函数:
def uncurry_2(f):
return lambda x, y: f(x)(y)
uncurried_range = uncurry_2(curried_range)
print(uncurried_range(1, 10))
这不是很好的风格,但您可以使用返回的 lambda
:
__closure__
属性访问闭包中的变量
>>> countup.__closure__[0].cell_contents
<function __main__.range_new>
这会访问您函数 curry_2
最内层闭包的内容(最内层 lambda
使用的变量),因此 returns 您在那里使用的函数。
但是在生产代码中你不应该使用它。最好为柯里化创建一个 class(或函数),它支持访问未柯里化的函数(lambda
没有提供)。但是 Python 中的一些函数工具支持访问 "decorated" 函数,例如 partial
:
>>> from functools import partial
>>> countup = partial(range_new, 1)
>>> print(countup(10))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> countup.func
<function __main__.range_new>
我相信 uncurry 是指您想让函数接受更多参数。您是否考虑过使用 "partial" 函数?它允许您在调用方法时使用任意数量的参数。
from functools import partial
def f(a, b, c, d):
print(a, b, c, d)
g = partial(partial(f, 1, 2), 3)
g(4)
实施它应该非常简单
def partial(fn, *args):
def new_func(*args2):
newArgs = args + args2
fn(*newArgs)
return new_func;
请注意原始问题中提供的代码,上面的代码称为部分应用程序。 Currying 通常比这更灵活——这里是你如何使用 Python 3 来做到这一点(它在 Python 2 中更棘手)。
def curry(fn, *args1):
current_args = args1
sig = signature(fn)
def new_fn(*args2):
nonlocal current_args
current_args += args2
if len(sig.parameters) > len(current_args):
return new_fn
else:
return fn(*current_args)
return new_fn
j = curry(f)
j(1)(2, 3)(4)
现在回到您的代码。 range_new 现在可以通过几种新方式使用:
print(range_new(1, 10))
curried_range = curry(range_new)
countup = curried_range(1)
print(countup(10))
countup_again = curried_range
print(countup_again(1, 10))