[Python标准库]functools——管理函数的工具

[Python标准库]functools——管理函数的工具
        作用:处理其他函数的函数。
        Python 版本:2.5 及以后版本
        functools 模块提供了一些工具来调整或扩展函数和其他可回调对象,而不必完全重写。
修饰符
        functools 模块提供的主要工具是 partial 类,它可以用来“包装”一个有默认参数的可回调对象。得到的对象本身是可回调的,可以看作就像是原来的函数。它与原函数的参数完全相同,调用时也可以提供额外的位置或命名参数。可以使用 partial 而不是 lambda 为函数提供默认参数,有些参数可以不指定。
        1. partial 对象
        下面这个例子显示了函数 myfunc() 的两个简单的 partial 对象。show_details() 的输出包含这个部分对象的 func、args 和 keywords 属性。
import functools

def myfunc(a, b=2):
    """Docstring for myfunc()."""
    print '  called myfunc with:', (a, b)
    return
    
def show_details(name, f, is_partial=False):
    """Show details of a callable object."""
    print '%s:' % name
    print '  object:', f
    if not is_partial:
        print '  __name__:', f.__name__
    if is_partial:
        print '  func:', f.func
        print '  args:', f.args
        print '  keywords:', f.keywords
    return
    
show_details('myfunc', myfunc)
myfunc('a', 3)
print

# Set a different default value for 'b', but require
# the caller to provide 'a'.
p1 = functools.partial(myfunc, b=4)
show_details('partial with named default', p1, True)
p1('passing a')
p1('override b', b=5)
print

# Set default value for both 'a' and 'b'.
p2 = functools.partial(myfunc, 'default a', b=99)
show_details('partial with named default', p2, True)
p2()
p2(b='override b')
print

print 'Insufficient arguments:'
p1()
        在这个例子的最后,调用了之前创建的第一个 partial,但没有为 a 传入一个值,这就导致一个异常。
        2. 获取函数属性
        默认情况下,partial 对象没有 __name__ 或 __doc__ 属性,如果没有这些属性,修饰的函数将更难调试。使用 update_wrapper() 可以从原函数将属性复制或添加到 partial 对象。
import functools

def myfunc(a, b=2):
    """Docstring for myfunc()."""
    print '  called myfunc with:', (a, b)
    return
    
def show_details(name, f):
    """Show details of a callable object."""
    print '%s:' % name
    print '  object:', f
    print '  __name__:',
    try:
        print f.__name__
    except AttributeError:
        print '(no __name__)'
    print '  __doc__:', repr(f.__doc__)
    print
    return
    
show_details('myfunc', myfunc)

p1 = functools.partial(myfunc, b=4)
show_details('raw wrapper', p1)

print 'Updating wrapper:'
print '  assign:', functools.WRAPPER_ASSIGNMENTS
print '  update:', functools.WRAPPER_UPDATES

functools.update_wrapper(p1, myfunc)
show_details('updated wrapper', p1)
        添加到包装器的属性在 WRAPPER_ASSIGNMENTS 中定义,而 WRAPPER_UPDATES 列出了要修改的值。
        3. 其他可回调对象
        Partial 适用于任何可回调对象,而不只是单独的函数。
import functools

class MyClass(object):
    """Demonstration class for functools"""
    
    def method1(self, a, b=2):
        """Docstring for method1()."""
        print '  called method1 with:', (self, a, b)
        return
    
    def method2(self, c, d=5):
        """Docstring for method2"""
        print '  called method2 with:', (self, c, d)
        return
    wrapped_method2 = functools.partial(method2, 'wrapped c')
    functools.update_wrapper(wrapped_method2, method2)

    def __call__(self, e, f=6):
        """Docstring for MyClass.__call__"""
        print '  called object with:', (self, e, f)
        return
    
def show_details(name, f):
    """Show details of a callable object."""
    print '%s:' % name
    print '  object:', f
    print '  __name__:',
    try:
        print f.__name__
    except AttributeError:
        print '(no __name__)'
    print '  __doc__:', repr(f.__doc__)
    return
    
o = MyClass()
    
show_details('method1 straight', o.method1)
o.method1('no default for a', b=3)
print
    
p1 = functools.partial(o.method1, b=4)
functools.update_wrapper(p1, o.method1)
show_details('method1 wrapper', p1)
print

show_details('method2', o.method2)
o.method2('no default for c', d=6)
print

show_details('wrapped method2', o.wrapped_method2)
o.wrapped_method2('no default for c', d=6)
print

show_details('instance', o)
o('no default for e')
print
p2 = functools.partial(o, f=7)
show_details('instance wrapper', p2)
p2('e goes here')
        这个例子由一个实例以及实例的方法来创建部分对象。
        4. 为修饰符获取函数属性
        在修饰符中使用时,更新包装的可回调对象的属性尤其有用,因为变换后的函数最后会得到原“裸”函数的属性。
import functools

def show_details(name, f):
    """Show details of a callable object."""
    print '%s:' % name
    print '  object:', f
    print '  __name__:',
    try:
        print f.__name__
    except AttributeError:
        print '(no __name__)'
    print '  __doc__:', repr(f.__doc__)
    print
    return

def simple_decorator(f):
    @functools.wraps(f)
    def decorated(a='decorated defaults', b=1):
        print '  decorated:', (a, b)
        print '  ',
        f(a, b=b)
        return
    return decorated

def myfunc(a, b=2):
    "myfunc() is not complicated"
    print '  myfunc:', (a, b)
    return

# The raw function
show_details('myfunc', myfunc)
myfunc('unwrapped, default b')
myfunc('unwrapped, passing b', 3)
print

# Wrap explicitly
wrapped_myfunc = simple_decorator(myfunc)
show_details('wrapped_myfunc', wrapped_myfunc)
wrapped_myfunc()
wrapped_myfunc('args to wrapped', 4)
print

# Wrap with decorator syntax
@simple_decorator
def decorated_myfunc(a, b):
    myfunc(a, b)
    return

show_details('decorated_myfunc', decorated_myfunc)
decorated_myfunc()
decorated_myfunc('args to decorated', 4)
        functools 提供了一个修饰符 wraps(),它会对所修饰的函数应用 update_wrapper()。
比较
        在 Python 2 中,类可以定义一个 __cmp__() 方法,后者会根据这个对象小于、等于还是大于所比较的元素返回 -1、0 或 1。Python 2.1 引入了富比较(rich comparison)方法 API(__lt__()、__le__()、__eq__()、__ne__()、__gt__() 和 __ge__()),可以完成一个比较操作并返回一个 Boolean 值。Python 3 则废弃了 __cmp__() 而代之以这些新方法,所以 functools 提供了一些工具,以便于编写 Python 2 类而且同时符合 Python 3 中新的比较需求。
        1. 富比较
        设计富比较 API 是为了支持涉及复杂比较的类,从而以最高效的方式实现各个测试。不过,对于比较相对简单的类,手动地创建各个富比较方法就没有必要了。total_ordering() 类修饰符取一个提供了部分方法的类,并添加其余的方法。
import functools
import inspect
from pprint import pprint

@functools.total_ordering
class MyObject(object):
    def __init__(self, val):
        self.val = val
    def __eq__(self, other):
        print '  testing __eq__(%s, %s)' % (self.val, other.val)
        return self.val == other.val
    def __gt__(self, other):
        print '  testing __gt__(%s, %s)' % (self.val, other.val)
        return self.val > other.val

print 'Methods:\n'
pprint(inspect.getmembers(MyObject, inspect.ismethod))

a = MyObject(1)
b = MyObject(2)

print '\nComparisons:'
for expr in [ 'a < b', 'a <= b', 'a == b', 'a >= b', 'a > b' ]:
    print '\n%-6s:' % expr
    result = eval(expr)
    print '  result of %s: %s' % (expr, result)
        这个类必须提供 __eq__() 和另外一个富比较方法的实现。修饰符会增加其余方法的实现,它们要利用类提供的比较来完成工作。
        2. 比对序
        由于 Python 3 中废弃了老式比较函数,因此 sort() 之类的函数中也不再支持 cmp 参数。对于使用了比较函数的 Python 2 程序,可以用 cmp_to_key() 将它们转换为一个返回比对键(collation key)的函数,这个键用于确定元素在最终序列中的位置。
import functools

class MyObject(object):
    def __init__(self, val):
        self.val = val
    def __str__(self):
        return 'MyObject(%s)' % self.val

def compare_obj(a, b):
    """Old-style comparison function."""
    print 'comparing %s and %s' % (a, b)
    return cmp(a.val, b.val)

# Make a key function using cmp_to_key()
get_key = functools.cmp_to_key(compare_obj)

def get_key_wrapper(o):
    """Wrapper function for get_key to allow for print statements."""
    new_key = get_key(o)
    print 'key_wrapper(%s) -> %s' % (o, new_key)
    return new_key
objs = [ MyObject(x) for x in xrange(5, 0, -1) ]

for o in sorted(objs, key=get_key_wrapper):
    print o
        正常情况下,可以直接使用 cmp_to_key(),不过这个例子中引入了一个额外的包装器函数,从而在调用 key 函数时可以输出更多的信息。
        如输出所示,sorted() 首先对序列中的每一个元素调用 get_key_wrapper() 来生成一个键。cmp_to_key() 返回的键是 functools 中定义的一个类的实例,这个类使用所传入的老式比较函数来实现富比较 API。所有键都创建之后,将通过比较这些键对序列排序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值