如何在Python中取消函数?

frh*_*yme 10 python functional-programming currying

最近,我使用标准ML研究了"编程语言" ,并且我学习了currying方法(或其他东西),所以我在Python中应用它.以下是简单的功能和currying.

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))
Run Code Online (Sandbox Code Playgroud)

结果如下.它运作良好; 与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]
Run Code Online (Sandbox Code Playgroud)

Flo*_*ker 15

最简单的解决方案是使用无法解决的代码再次包装curried函数:

def uncurry_2(f):
    return lambda x, y: f(x)(y)

uncurried_range = uncurry_2(curried_range)
print(uncurried_range(1, 10))
Run Code Online (Sandbox Code Playgroud)


MSe*_*ert 7

它不是完全好的样式,但您可以使用返回的(可能仅CPython)__closure__属性访问闭包中的变量lambda:

>>> countup.__closure__[0].cell_contents
<function __main__.range_new>
Run Code Online (Sandbox Code Playgroud)

这将访问lambda函数中最内层闭包(最里面的变量)的内容curry_2,从而返回您在那里使用的函数.

但是在生产代码中,您不应该使用它.最好创建一个用于currying的类(或函数)来支持访问未处理的函数(这是lambda不提供的).但是Python中的一些functools支持访问"装饰"功能,例如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>
Run Code Online (Sandbox Code Playgroud)


Par*_*ris 6

我相信你的意思是你想让这个函数接受更多的论点.你考虑过使用"部分"功能吗?它允许您在调用方法时根据需要使用尽可能多的参数.

from functools import partial

def f(a, b, c, d):
  print(a, b, c, d)

g = partial(partial(f, 1, 2), 3)
g(4)
Run Code Online (Sandbox Code Playgroud)

实施它应该非常简单

def partial(fn, *args):
  def new_func(*args2):
    newArgs = args + args2
    fn(*newArgs)

  return new_func;
Run Code Online (Sandbox Code Playgroud)

请注意原始问题中提供的代码,上面的代码称为部分应用程序.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)
Run Code Online (Sandbox Code Playgroud)

现在回到你的代码.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))
Run Code Online (Sandbox Code Playgroud)