17

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

  • 根据更一般的,可能是内部使用的功能,明确定义有用的功能;或者,
  • 使用部分函数应用程序来显式描述函数柯里化?

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

假设编写了一个函数 _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

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

显然,这个意图在函数柯里化方面更好地表达了。

# Curried function definition style
import functools
identity_ordering = functools.partial(_sort_by_score, _identity_scoring)
reversed_ordering = functools.partial(_sort_by_score, _reversed_scoring)

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

>>> foo = [1, 2, 3, 4, 5]
>>> identity_ordering(foo)
[1, 2, 3, 4, 5]
>>> reversed_ordering(foo)
[5, 4, 3, 2, 1]

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

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

柯里化函数定义风格的明显优势:

  1. 惯用地表达函数式编程的意图;
  2. 由于简洁,代码看起来不错。

对于定义“有用”的功能,两种风格中的哪一种更受欢迎?还有其他更惯用/ Pythonic /等的样式吗?

4

2 回答 2

13

如果您想将柯里化函数作为公共接口的一部分,请使用显式函数定义。这具有以下附加优势:

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

  2. 浏览模块源代码时,真正的函数定义更容易浏览。

我会functools.partial()以与 lambda 表达式类似的方式使用,即用于本地需要的一次性函数。

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

sort_by_score(identity_scoring, foo)

这对我来说似乎是最明确的。

于 2011-02-23T13:48:57.203 回答
2

作为一个小切线,通常希望让sorted内置函数尽可能多地完成 decorate-sort-undecorate 工作。例如:

def _sort_by_score(scoring, items_list):
    num_items = len(items_list)
    def score(entry):
        return scoring(num_items, entry[0])
    return [item for position, item in sorted(enumerate(items_list), key=score)]

(仅作为答案发布,因为代码块不能用作评论。有关实际问题的答案,请参阅 Sven 的回复)

由其他人编辑:Python 排序函数遍历列表并首先生成键列表。对于每个列表项,该key()函数仅按输入列表的顺序调用一次。因此,您还可以使用以下实现:

def _sort_by_score(scoring, items_list):
    num_items = len(items_list)
    index = itertools.count()
    def score(entry):
        return scoring(num_items, next(index))
    return sorted(items_list, key=score)

(仅作为修订发布,因为代码块不能用作注释。)

于 2011-02-23T14:06:22.940 回答