functools模块
来源:互联网 发布:韩国语常用语网络 编辑:程序博客网 时间:2024/05/20 11:22
1 functools函数
functools模块用于高阶函数:作用与或者返回其它函数的函数。一般来说,对于该模块,任何可调用对象都可以视为一个函数。
functools模块定义了以下函数:
1.1 functools.cmp_to_key(func)
版本3.2中新增。
将旧风格的比较函数转换为key函数。用于接收key函数的工具(例如sorted()
,min()
,max()
,heapq.nlargest()
,heapq.nsmallest()
,itertools.groupby()
)。该函数主要用作支持比较函数的Python 2转换工具。
比较函数可以是任何可调用的对象,接收两个参数,比较它们,如果小于返回负数,相等返回0,大于返回正数。key函数是一个可调用对象,接收一个参数,并返回另一个值用于排序的键。
示例:
sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order
1.2 @functools.lru_cache(maxsize=128, typed=False)
版本3.2中新增。版本3.3中修改:增加可选参数typed参数。
装饰器用一个有记忆的调用包装一个函数,它可以保存最近maxsize次调用。当使用同样的参数定期调用费时或I/O绑定的函数时,它可以节省时间。
因为使用字典缓存结果,所以函数的位置和关键字参数必须是hashable。
如果maxsize设置为None,则禁用LRU功能,并且缓存可以无限增长。当maxsize设置为
如果typed设置为真,则不同类型的函数参数会分别缓存。例如,f(3)
和f(3.0)
将视为不同结果的不同调用。
为了帮助测量缓存的有效性并调整maxsize参数,包装函数使用cache_info()
函数返回一个命名元组,包括hits,misses,maxsize和currsize。在多线程环境中,hits和misses是近似值。
装饰器还提供了cache_clear()
函数用于清除缓存,或者让缓存失效。
原始的底层函数通过wrapped属性访问。这对于内省,绕过缓存,或者重新装饰函数很有用。
当最近调用是即将调用的最佳调用因子时(例如,新闻服务器上的最受欢迎文章常常每天改变),LRU(least recently used)缓存效果最好。缓存的大小限制确保缓存不会在长时间运行的进程(如web服务器)上不受限制的增长。
用于静态Web内容的LRU缓存示例:
@lru_cache(maxsize=32)def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' resource = 'http://www.python.org/dev/peps/pep-%04d/' % num try: with urllib.request.urlopen(resource) as s: return s.read() except urllib.error.HTTPError: return 'Not Found'>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:... pep = get_pep(n)... print(n, len(pep))>>> get_pep.cache_info()CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
使用缓存实现动态编程技术高效计算斐波那契数列的示例:
@lru_cache(maxsize=None)def fib(n): if n < 2: return n return fib(n-1) + fib(n-2)>>> [fib(n) for n in range(16)][0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]>>> fib.cache_info()CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
1.3 @functools.total_ordering
版本3.2中新增。版本3.4中修改:如果是不能识别的类型,现在支持从底层比较函数返回NotImplemented。
给定的一个类定义了一个或多个富比较方法,该类装饰器提供剩下的。这简化了指定所有富比较操作的工作量。
类必须定义__lt__()
,__le__()
,__gt__()
或__ge__()
的其中一个。此外,类应该提供一个__eq__()
方法。
示例:
@total_orderingclass Student: def _is_valid_operand(self, other): return (hasattr(other, 'lastname') and hasattr(other, 'firstname')) def __eq__(self, other): if not self._is_valid_operand(other): return NotImplemented return ((self.lastname.lower(), self.firstname.lower()) == (other.lastname.lowher(), other.firstname.lower())) def __lt__(self, other): if not self._is_valid_operand(other): return NotImplemented return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower()))
注意:虽然该装饰器能很容易的创建行为良好的完全有序类型,但会导致衍生出的比较函数执行的更慢,以及更复杂的堆栈跟踪。如果性能基准测试表明这是程序的瓶颈,则实现所有六个富比较函数可能会是提高速度的方式。
1.4 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()
用于冻结函数的某些参数和/或关键字参数,生成一个简化的签名对象。例如,用于创建一个类似int()
函数的可调用对象,其中base参数默认为2:
>>> from functools import partial>>> basetwo = partial(int, base=2)>>> basetwo.__doc__ = 'Convert base 2 string to an int.'>>> basetwo('10010')18
1.5 类方法 functools.partialmethod(func, *args, **keywords)
版本3.4中新增。
返回一个行为类似partial的新partialmethod描述符,除了它是用于方法定义,而不是直接调用。
func必须是一个descriptor或者可调用对象(两个对象都像常规函数一样作为descriptor)。
当func是一个descriptor(比如普遍的Python函数,classmethod()
,staticmethod()
,abstractmethod()
,或者其它partialmethod实例时,get的调用会委托给底层的descriptor,并返回一个适当的partial对象。
当func不是可调用的descriptor时,会动态创建一个适当的绑定方法。用于方法时,该行为类似普通的Python函数:self参数会插入为第一个位置参数,甚至在传递给partialmethod构造器的args和keywords之前。
示例:
>>> class Cell(object):... def __init__(self):... self._alive = False... @property... def alive(self):... return self._alive... def set_state(self, state):... self._alive = bool(state)... set_alive = partialmethod(set_state, True)... set_dead = partialmethod(set_state, False)...>>> c = Cell()>>> c.aliveFalse>>> c.set_alive()>>> c.aliveTrue
1.6 functools.reduce(function, iterable[, initializer])
将两个参数的function从左至右依次作用于序列中的项,减少序列为单个值。例如,reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
会计算((((1+2)+3)+4)+5)
。左边的参数x是计算出的值,右边的参数y是从序列中更新的值。如果提供了可选参数initializer,在计算中,它会放在序列项之前,当序列为空时,提供一个默认值。如果没指定initializer,并且序列只有包含一项,会返回第一项。
大致等价于:
def reduce(function, iterable, initializer=None): it = iter(iterable) if initializer is None: value = next(it) else: value = initializer for element in it: value = function(value, element) return value
1.7 @functools.singledispatch(default)
版本3.4中新增。
将函数转换为single-dispatch generic函数。
使用@singledispatch装饰器定义generic函数。注意,dispatch发生在第一个参数的类型上,相应的创建函数:
>>> from functools import singledispatch>>> @singledispatch... def fun(arg, verbose=False):... if verbose:... print('Let me juset say,', end=' ')... print(arg)
使用generic函数的register()
属性添加函数的重载实现。这是一个装饰器,接受一个类型参数,并装饰实现该类型操作的函数:
>>> @fun.register(int)... def _(arg, verbose=False):... if verbose:... print('Strength in numbers, eh?', end=' ')... print(arg)...>>> @fun.register(list)... def _(arg, verbose=False):... if verbose:... print('Enumerate this:')... for i, elem in enumerate(arg):... print(i, elem)
为了能够注册lambda表达式和预先存在的函数,register()
可以用于函数形式:
>>> def nothing(arg, verbose=False):... print('Nothing.')...>>> fun.register(type(None), nothind)
register()
属性返回未装饰的函数,可以使用装饰堆叠,pickling,以及为每个变体单独创建单元测试:
>>> @fun.register(float)... @fun.register(Decimal)... def fun_num(arg, verbose=False):... if verbose:... print('Half of your number:', end=' ')... print(arg / 2)...>>> fun_num is funFalse
调用时,generic函数根据第一个参数的类型dispatch:
>>> fun('Hello World.')Hello World.>>> fun('test.', verbose=True)Let me just say, test.>>> fun(42, verbose=True)Strength in numbers, eh? 42>>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)Enumerate this:0 spam1 spam2 eggs3 spam>>> fun(None)Nothing.>>> fun(1.23)0.615
当没有注册特定类型的实现时,其方法解析顺序用于查找更通用的实现。用@singledispatch
装饰的原始函数是为object类型注册的,如果没有找到更好的实现,则使用它。
使用dispatch()
属性查看generic函数为指定类型选择哪个实现:
>>> fun.dispatch(float)<function fun_num at 0x1035a2840>>>> fun.dispatch(dict)<function fun at 0x103fe0000>
使用只读属性registry
访问所有注册的实现:
>>> fun.registry.keys()dict_keys([<class 'NoneType'>, <class 'int'>, <class 'object'>, <class 'decimal.Decimal'>, <class 'list'>, <class 'float'>])>>> fun.registry[float]<function fun_num at 0x1035a2840>>>> fun.registry[object]<function fun at 0x103fe0000>
1.8 functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
版本3.2中新增:自动添加__wrapped__属性。版本3.2中新增:默认拷贝__annotations__属性。版本3.2中修改:缺少属性不再触发AttributeError。版本3.4中修改:现在__wrapped__属性总是引用wrapped函数,即使该属性定义了__wrapped__属性。
更新一个wrapper函数,让它看起来像一个wrapped函数。可选参数是元组,用来指定原函数的哪些属性直接分配给wrapper函数的匹配属性,wrapper函数的哪些属性从原函数的相应属性更新。这些参数的默认值是模块级别的常量WRAPPER_ASSIGNMENTS(分配wrapper函数的__module__
,__name__
,__qualname__
,__annotations__
和文档字符串__doc__
)和WRAPPER_UPDATES(哪些更新wrapper函数的__dict__
,比如实例的字典)。
为了内省和其它目的(比如绕过缓存装饰器lru_cache()
)允许访问原始函数,该函数自动在wrapper函数添加一个__wrapped__
属性,应用wrapped函数。
该函数的主要用途是,在装饰器函数中包装被装饰的函数,并返回wrapper。如果wrapper函数没有更新,返回函数的元数据将反射wrapper的定义,而不是原始函数的定义,原始函数的定义通常没有意义。
除了函数,update_wrapper()
可以与其它可调用对象一起使用。出现在assigned或updated参数中,而不在被包装对象中的任何属性都会被忽略(比如,该函数不会试图在wrapper函数中设置它们)。如果wrapper函数本身缺少updated中的属性,仍然会抛出AttributeError。
1.9 @functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
这是一个便捷函数,定义一个wrapper函数时,作为函数装饰器调用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 functionCalled example function>>> example.__name__'example'>>> example.__doc__'Docstring'
没有使用这个装饰工厂,example函数的名称将是’wrapper’,并且原始example()
的docstring将会丢失。
2 partial对象
partial()
创建可调用的partial对象。它们有三个只读属性:
2.1 partial.func
一个可调用的对象或函数。调用partial对象会转为使用新的参数和关键字参数调用func。
2.2 partial.args
最左边的位置参数会优先作为位置参数提供给partial对象调用。
2.3 partial.keywords
partial对象被调用时提供关键字参数。
partial对象与函数对象类似,它们可以被调用,有弱引用,并且可以有属性。但有一些重要的区别。对于实例,__name__
和__doc__
属性不会自动创建。同时,在类中定义的partial对象的行为类似静态方法,在实例属性查找时,不会转换为绑定方法。
- functools模块
- functools模块
- python模块 - functools模块
- Python的functools模块
- Python的functools模块
- Python的functools模块
- Python的functools模块
- Python的functools模块
- Python模块(functools)
- Python的functools模块
- python functools模块
- PYTHON-FUNCTOOLS模块
- Python functools模块学习总结
- python的functools进阶模块
- Python的functools模块详解
- functools
- functools
- functools
- poj 1308
- 数据库连接池c3p0和dbcp
- ubuntu下(wifi)硬件开关控制的设置
- PreferenceActivity练习
- java学习笔记(十五)继承
- functools模块
- Java 二维码生成与解析
- ASO优化之教你如何得到ASO优化100关键词字符
- 自定义view——Path之基本操作(转载)-8
- Go语言小知识之map遍历
- SpringMVC集成Spring-Session进行分布式管理
- 线性代数笔记-2-矩阵消元
- ueditor 添加支持文件存储到文件服务器
- C#中的invoke方法