在Python中,部分函数应用(currying)与显式函数定义

Ade*_*mro 16 python functional-programming currying partial-application

在Python中,它被认为是更好的风格:

  • 根据更一般的,可能是内部使用的函数明确定义有用的函数; 要么,
  • 使用部分函数应用程序来明确描述函数currying?

我将通过一个人为的例子来解释我的问题.

假设有人编写一个函数_sort_by_scoring,它接受两个参数:评分函数和项列表.它返回原始列表的副本,该副本按照每个项目在原始列表中的位置的分数排序.还提供了两个示例评分函数.

def _sort_by_score(scoring, items_list):
    unsorted_scored_list = [(scoring(len(items_list), item_position), item) for item_position, item in enumerate(items_list)]
    sorted_list = [item for score, item in sorted(unsorted_scored_list)]
    return sorted_list

def _identity_scoring(items_list_size, item_position):
    return item_position

def _reversed_scoring(items_list_size, item_position):
    return items_list_size - item_position
Run Code Online (Sandbox Code Playgroud)

函数_sort_by_score永远不会直接调用; 相反,它由其他单参数函数调用,它将评分函数及其唯一参数(项目列表)传递给_sort_by_scoring并返回结果.

# Explicit function definition style
def identity_ordering(items_list):
    return _sort_by_score(_identity_scoring, items_list)

def reversed_ordering(items_list):
    return _sort_by_score(_reversed_scoring, items_list)
Run Code Online (Sandbox Code Playgroud)

显然,这个意图在函数currying方面表达得更好.

# Curried function definition style
import functools
identity_ordering = functools.partial(_sort_by_score, _identity_scoring)
reversed_ordering = functools.partial(_sort_by_score, _reversed_scoring)
Run Code Online (Sandbox Code Playgroud)

用法(在任何一种情况下):

>>> foo = [1, 2, 3, 4, 5]
>>> identity_ordering(foo)
[1, 2, 3, 4, 5]
>>> reversed_ordering(foo)
[5, 4, 3, 2, 1]
Run Code Online (Sandbox Code Playgroud)

显式函数定义样式的明显优势:

  1. 可以在更一般的函数之前定义有用的函数,而不需要引发NameErrors;
  2. 辅助函数(例如,评分函数)可以在函数定义体中定义;
  3. 可能更容易调试;
  4. 代码看起来很好,因为"显式优于隐式".

curried函数定义风格的明显优势:

  1. 用惯用语表达函数式编程的意图;
  2. 代码看起来很好,因为简洁.

为了定义"有用"功能,首选哪两种样式?还有其他风格更惯用/ Pythonic /等?

Sve*_*ach 13

如果要将curried函数作为公共接口的一部分,请使用显式函数定义.这具有以下额外优势:

  1. 将docstring分配给显式函数定义更容易.对于partial()函数,您必须分配__doc__属性,这有点难看.

  2. 浏览模块源时,实际函数定义更容易浏览.

我将以functools.partial()类似于lambda表达式的方式使用,即用于本地需要的丢弃函数.

在您的特定示例中,我可能不使用,删除前导下划线并调用

sort_by_score(identity_scoring, foo)
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎最明确.