Python——functools

  该模块为高阶函数提供支持——作用于或返回函数的函数被称为高阶函数。在该模块看来,一切可调用的对象均可视为本模块中所说的“函数”。

  目录

  一、模块方法

    1. functools.cmp_to_key(func)

    2. functools.total_ordering(cls)

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

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

    5. functools.update_wrapper(wrapper, wrapped[, assigned][, updated])

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

  二、partial对象

    1. partial.func

    2. partial.args

    3. partial.keywords

 

一、模块方法

  该模块中定义了如下方法:

1.

functools.cmp_to_key(func) 

  将老式的比较函数(comparison function)转化为关键字函数(key function)。与接受key function的工具一同使用(如 sorted(), min(), max(), heapq.nlargest(), itertools.groupby())。该函数主要用来将程序转成 Python 3 格式的,因为 Python 3 中不支持比较函数。

  比较函数是可调用的,接受两个参数,比较这两个参数并根据他们的大小关系返回负值、零或正值中的某一个。关键字函数也是可调用的,接受一个参数,同时返回一个可以用作排序关键字的值。

  例如:

sorted(iterable, key=cmp_to_key(locale.strcoll))

 

2.

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

 

3. 

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

  和 reduce() 方法的作用相同,这里提供了向 Python 3 过渡的前向支持。

 

4. 

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

  函数装饰器,返回一个新的 partial 对象,关于 partial 对象的介绍见下文。调用 partial 对象就和调用被修饰的函数 func 相同,只不过调用 partial 对象时传入的参数个数通常少于调用 func 时传入的参数个数。 当一个函数 func 可以接收很多参数,而某一次使用只需要更改其中的一部分参数,其他的某些参数都保持不变时, partial 对象就可以将这些不变的对象冻结起来,这样调用 partial 对象时传入未冻结的参数, partial 对象调用 func 时连同已经被冻结的参数一同传给 func 函数,从而简化了调用过程。

  如果调用 partial 对象时提供了更多的参数,那么他们会被添加到 args 的后面,如果提供了更多的关键字参数,那么它们将扩展或覆写已经冻结的关键字参数

   partial 对象的作用大抵如下:

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 对象创建一个 base 参数始终为 2 的 int()

from functools import partial

basetwo = partial(int, base=2)
basetwo.__doc__ = 'Convert base 2 string to an int.'
basetwo('10010')

  这个新的 partial 对象 basetwo 能够将二进制的参数转化为十进制的整型结果,在调用这个 partial 对象时只需要传入二进制的目标参数即可。

 

5.

 functools.update_wrapper(wrapper, wrapped[, assigned][, updated]) 

  更新一个包裹(wrapper)函数,使其看起来更像被包裹(wrapped)的函数。

  可选的参数指定了被包裹函数的哪些属性直接赋值给包裹函数的对应属性,同时包裹函数的哪些属性要更新而不是直接接受被包裹函数的对应属性。参数 assigned 的默认值对应于模块级常量 WRAPPER_ASSIGNMENTS (默认地将被包裹函数的 __name__, __module__ 和 __doc__ 属性赋给包裹函数), 参数 updatedd  的默认值对应于模块级常量 WRAPPER_UPDATES (默认更新 wrapper 函数的 __dict__ 属性)。

  这个函数的主要用途是在一个装饰器中,原函数会被装饰(包裹),装饰器函数会返回一个 wrapper 函数,如果装饰器返回的这个 wrapper 函数没有被更新,那么它的一些元数据更多的是反映 wrapper 函数定义时的特征,无法反映 wrapped 函数的特性。

 

6.

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

  这个函数可以用作一个装饰器,简化调用上一个函数 update_wrapper 的过程。调用这个函数等价于调用  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() 函数是经过 @my_decorator 装饰的,装饰器的作用是接受一个被包裹函数作为参数,对其进行加工,返回一个包裹函数。代码使用 @functools.wraps 装饰将要返回的包裹函数 wrapper,使得他的 __name__, __doc__ 和 __module__ 属性与被装饰函数 examle()完全相同, 这样虽然最终调用的是经过装饰的 example() 函数,但是某些属性还是得到了维护。

  如果在 @my_decorator 的定义中不使用 @functools.wraps 装饰包裹函数,那么最终 example.__name__ 将会变为 ‘wrapper’, 而 example.__doc__ 也会丢失。

 

partial对象

  partial对象是调用partial()时创建的可调用对象,他们有三个只读的属性:

 

1.  partial.func 

  可调用或函数,调用partial对象时,会结合新的参数和关键字最终调用func。

 

2.  partial.args 

  默认为最左的位置参数,这些参数会被自动添加到所有调用partial对象时传入的参数前。也就是说在调用partial对象时不用传入这些参数即可,他们视为恒定的,从而自动添加到func的调用中。

 

3.  partial.keywords 

  当调用partial对象时提供的关键字参数。

 

  partial对象在一些方面类似于函数对象:可调用,弱引用,可以拥有属性。但是也有一些关键的区别:

  1.partial对象的 __name__ 和 __doc__ 属性不会自动创建;

  2. 在类里定义的partial对象使用时更像静态方法,在实例的属性查询过程中不会转变成绑定方法(bound methods, 通过类的实例对象进行属性引用)。

posted @ 2014-12-17 11:46 王智愚 阅读(...) 评论(...) 编辑 收藏