9.8. functools — 高阶函数和可调用对象的操作

2.5版中新增。

源代码: Lib/functools.py

functools 模块提供了高阶函数功能:函数可以作为或者返回其他函数。通常,为了本模块的目的,任何可调用对象都可以被视为功能。

functools 模块定义了如下函数:

functools.cmp_to_key(func)

把一个老式的比较函数转换为一个关键函数。需要和接受关键函数作为参数的函数一起使用 (比如 sorted(), min(), max(), heapq.nlargest(), heapq.nsmallest(), itertools.groupby()).当程序转换到 Python 3 后比较函数不再被支持, 这个函数主要用来实现这种转换的工具。

比较函数是任何一个可调用的函数,且包含两个参数,对参数进行比较,如果小于返回负数,等于返回0,大于返回正数。关键函数是一种可调用函数。接受一个参数,返回另一个表明其在期望序列中的位置的值。

示例:

sorted(iterable, key=cmp_to_key(locale.strcoll))  # locale-aware sort order

2.7 版中新增。

functools.total_ordering(cls)

给定一个定义了一个或多个富比较排序方法的类,该方法提供了一个类装饰器。这简化了指定所有可能的富比较操作的工作量。

这个类必须要定义 __lt__(), __le__(), __gt__(), 或 __ge__()方法中的任何一个。此外, 这个类还应该提供一个 __eq__() 方法。

示例:

@total_ordering
class Student:
    def __eq__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) ==
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) <
                (other.lastname.lower(), other.firstname.lower()))

2.7 版中新增。

functools.reduce(function, iterable[, initializer])

该函数和 reduce() 相同.使用它可以允许编写的代码更能向前兼容 Python 3 。

2.6 版中新增。

functools.partial(func[,*args][, **keywords])

返回一个新的 partial 对象,该对象被调用的时候,其行为像调用带位置参数 args 和关键字参数 keywords 的函数 func如果提供多个参数调用, 它们会被追加给 args如果提供额外的关键字参数, 它们会扩展和覆盖 keywords大致相当于:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

partial() 用于偏函数应用。偏函数是指把一个函数的部分位置参数和/或关键字参数“冻结”,返回一个新的简化了的函数对象。例如, partial() 可以用来创建一个可调用的,行为像 int() 函数,但是base的参数默认值为 2 :

>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
functools.update_wrapper(wrapper, wrapped[, assigned][, updated])

更新一个 wrapper 函数让其更像一个 wrapped 函数。可选的参数是一个元祖,来指定原函数哪些属性被直接分配给装饰器中的匹配属性 ,哪些装饰器属性使用来自原函数的相应属性来更新。这些参数的默认值是模块级别的常数 WRAPPER_ASSIGNMENTS (分配给包装器函数: __name__, __module____doc__, 文档字符串) 和 WRAPPER_UPDATES (更新包装器函数: __dict__, 等实例的字典).

此函数的主要用途是 decorator 函数, 它包装装饰函数并返回包装器。如果不更新包装器函数,返回的函数的元数据将反射包装器的定义,而不是原函数的定义 ,这通常是没有意义的。

functools.wraps(wrapped[, assigned][, updated])

这是用来调用 partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)函数的方便函数。 当定义一个包装函数的时候作为一个函数装饰器。示例:

>>> from functools import wraps
>>> def my_decorator(f):
...     @wraps(f)
...     def wrapper(*args, **kwds):
...         print 'Calling decorated function'
...         return f(*args, **kwds)
...     return wrapper
...
>>> @my_decorator
... def example():
...     """Docstring"""
...     print 'Called example function'
...
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'

如果没有使用装饰器工厂,example函数名称会是 'wrapper', 且原函数 example() 的文档字符串会丢失。

9.8.1. partial 对象

partial 对象是由 partial() 创建的可调用对象。它们有三个只读属性:

partial.func

一个可调用对象或函数。调用 partial 对象会转而调用带有新位置参数和关键字参数的 func

partial.args

最左边的位置参数将被注入给一个 partial 对象调用作为其位置参数。

partial.keywords

关键字参数会在 partial 对象被调用的时候提供

partial 对象像一个 function 对象,因为它们是可调用的,弱引用,并且可以具有属性。它们有一些重要的区别。比如, the __name__ and __doc__ 属性不会自动创建。此外 partial 对象定义在类中,行为像静态方法,并且在实例属性查找的时候,不会转化为绑定方法。