天天看点

【Python模块】functools —— 作用于可调用对象的高阶函数集合

    英文原文出自:https://docs.python.org/2/library/functools.html

    functools 是一系列高阶函数的集合,这些函数可以接受其他函数作为参数或者返回其他函数。一般说来,凡是可被调用的对象,都可以当成这个模块的作用对象。

    functools 模块定义了下面的一系列函数:

functools.

cmp_to_key

(func)

    cmp_to_key可以将老式风格的比较函数转换成比较关键字函数。这个函数用在接收比较关键字函数作为参数的函数中(比如 

sorted()

min()

max()

heapq.nlargest()

heapq.nsmallest()

itertools.groupby()

)。因为在Python3中不再支持老式风格的比较函数,这个函数也常被当成把python2的函数转向python3的工具。

    老式风格的比较函数是指,接收两个参数进行比较,如果一个前者小于后者返回一个负数,前者等于后者返回0,前者大于后者返回一个正数。比较关键字函数是指接收一个参数,返回另外一个结果作为排序的关键字。

    应用举例:

from functools import cmp_to_key
def cmfunc(x,y):
    if x>y:
        return 1
    elif x==y:
        return 0
    else:
        return -1

seq=[2,1,4,5,3]
seq = sorted(seq,key=cmp_to_key(cmfunc))
for r in seq:
    print r
           

          输出结果:

[email protected]:~/projects/PythonTs$ python cmp_to_keyTs.py 
1
2
3
4
5
           

         查看更多排序的例子或者相关文档请查看 Sorting HOW TO .

functools.

total_ordering

(cls)

   如果一个类中含有一个以上的用于比较的方法,这个类级别的修饰器会补充剩下的部分用于比较的方法,它简化了在类中定义比较方法的繁重工作。

   这个被修饰的类必须定义以下方法之一 

__lt__()

__le__()

__gt__()

, or 

__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()))
           

           我们定义了Student类,只声明了__eq__和__lt__方法,当Student类被total_ordering修饰后,使用dir查看Student的属性,其他剩余的比较函数都被自动定义:

>>> from total_orderingTs import Student
>>> dir(Student)
['__doc__', '__eq__', '__ge__', '__gt__', '__le__', '__lt__', '__module__']
>>> 
           

functools.

reduce

(function, iterable[, initializer])

   这个函数和reduce的功能一样,它在functools模块创建只是为了使python3向前兼容。

  使用举例:

from functools import reduce
def add(x,y):
    return x+y

print reduce(add,[1,2,3,4,5])
           

           reduce的功能是将list中的前两个值作为参数传给add函数,然后将add的结果和第三个值再次传给add函数,以此类推,最终返回一个结果:

[email protected]:~/projects/PythonTs$ python reduceTs.py 
15
           

functools.

partial

(func[,*args][, **keywords])¶

         返回一个新的partial(偏函数)对象,partial被调用时就像传给它的func函数带着参数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 newfun
           

          partial()通过"冻结"一个函数的部分参数而获取一个偏函数对象,相当于简化了原函数的签名。比如说 partial()可以创建一个行为类似于base为2的int()函数:

>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
           

         应用举例:

from functools import partial
def add(x,y,z):
    return x+y+z

newadd=partial(add,y=1,z=2)
print newadd(3)
print newadd(55555)
           

          我们用partial定义新的函数newadd,但是简化了参数列表,只传入一个参数即可。

functools.

update_wrapper

(wrapper, wrapped[, assigned][, updated])

       使修饰函数更加符合被修饰函数。该函数中的后面可选参数是两组元组,前者用来指定从被修饰函数中获取哪些属性给修饰函数,后者用来指定修饰函数中哪些属性需要更新和被修饰函数一致。这些参数的默认值都是模块级别的约束,如WRAPPER_ASSIGNMENTS (在修饰函数中增加 __name__, __module__ 和 __doc__这些文档属性)和WRAPPER_UPDATES (更新修饰函数的__dict__属性)

       这个函数最主要的用处就是用在装饰器中。如果装饰器中的修饰函数没有被更新,装饰器的返回函数的元数据将会映射修饰函数而非被修饰函数。

functools.

wraps

(wrapped[, assigned][, updated])

    这个函数作为装饰器,在定义修饰函数的时候可以很方便的激活update_wrapper。它等价于partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)。       应用举例:

from functools import wraps


def decoratorWithoutWraps(f):
    def wrapper_func(args):
        """wrapper doc"""
        return f(args)
    return wrapper_func

@decoratorWithoutWraps
def wrapped_func1(args):
    """wrapped1 doc"""
    pass

def decoratorWithWraps(f):
    @wraps(f)
    def wrapper_func():
        """wrapper doc"""
        return f()
    return wrapper_func

@decoratorWithWraps
def wrapped_func2():
    """wrapped2 doc"""
    pass

if __name__ =='__main__':
    #without @wraps
    print wrapped_func1.__name__
    print wrapped_func1.__doc__
    #with @wraps
    print wrapped_func2.__name__
    print wrapped_func2.__doc__
           

    执行结果:

[email protected]:~/projects/PythonTs$ python wrapperTs.py
wrapper_func
wrapper doc
wrapped_func2
wrapped2 doc
           

    对于修饰器函数前没有使用@wraps的,打印出来的结果是定义的修饰器函数的__name__和__doc__,而对于修饰器前使用@wraps的,打印出来的是被修饰函数的 __name__和__doc__,显然后者才是我们期望的。

 Github位置:

https://github.com/HymanLiuTS/PythonTs

克隆本项目:

git clone [email protected]:HymanLiuTS/PythonTs.git

获取本文源代码:

git checkout PL02