Python标准库: functools (cmp_to_key, lru_cache, total_ordering, partial, partialmethod, reduce, singledispatch, update_wrapper, wraps)

functools模块处理的对象都是其他的函数,任何可调用对象都可以被视为用于此模块的函数。

1. functools.cmp_to_key(func)
因为Python3不支持比较函数,cmp_to_key就是将老式的比较函数(comparison function)转换成关键字函数(key function),与能够接受key function的函数一起使用,比如说sorted,list.sort, min, max, heapq.nlargest, itertools.groupby等等。

例子:

    from functools import cmp_to_key
    def compare(x1, x2):
        return x1 - x2

    a = [2, 3, 1]
    print(sorted(a, key=cmp_to_key(compare)))
    a.sort(key=cmp_to_key(compare))
    print(a)

输出:

[1, 2, 3]
[1, 2, 3]

 

2. @functools.lru_cache(maxsize=128, typed=False)
lru_cache可以作为装饰器将函数计算耗时的结果缓存起来,用来节省时间。
由于是使用字典进行的缓存,因此函数的关键字参数和位置参数必须是可哈希的。
如果maxsize=None,禁用lru功能,并且缓存可以无限制的增长。
当maxsize为2的幂次方时,lru的性能最好。

如果将typed设置为true,将单独缓存不同类型的函数参数,比如F(3)和F(3.0)将被视为不同结果的不同调用。

cache_info()函数可以用来测量缓存的有效性和优化maxsize参数。该函数返回一个命中、未命中、maxSize和currSize的命名的元组。
例子:

    from functools import lru_cache

    @lru_cache(maxsize=32)
    def get_pep(num):
        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))

    print(get_pep.cache_info())

    @lru_cache(maxsize=None)
    def fib(n):
        if n < 2:
            return n
        return fib(n-1) + fib(n - 2)

    print([fib(n) for n in range(16)])
    print(fib.cache_info())

  

3. @functools.total_ordering
指定一个已经定义了一个或者多个比较排序方法的类,这个类修饰器提供其余的方法。
这个类必须已经定义了__lt__(), __le__(), __gt__(), __ge__()中的一个,并且定义了__eq__()

    from functools import total_ordering

    @total_ordering
    class Student:

        def __init__(self, first_name, last_name):
            self.first_name = first_name
            self.last_name = last_name

        @staticmethod
        def _is_valid_operand(other):
            return hasattr(other, "last_name") and hasattr(other, "first_name")

        def __eq__(self, other):
            if not self._is_valid_operand(other):
                return NotImplemented
            return ((self.last_name.lower(), self.first_name.lower()) ==
                    (other.last_name.lower(), other.first_name.lower()))

        def __lt__(self, other):
            if not self._is_valid_operand(other):
                return NotImplemented
            return ((self.last_name.lower(), self.first_name.lower()) <
                    (other.last_name.lower(), other.first_name.lower()))

    a = Student(first_name="tom", last_name="hancs")
    b = Student(first_name="tom", last_name="hancs")
    print(a == b)
    print(a <= b)
    print(a >= b)

  

如果不使用total_ordering对装饰器进行装饰的话,使用<=或者>=会报错:

Traceback (most recent call last):
  File "D:/LearnProject/performance/functools_test.py", line 33, in <module>
    print(a <= b)
TypeError: ‘<=‘ not supported between instances of ‘Student‘ and ‘Student‘

4. functools.partial(func, *args, **keywords)
partial()用于冻结函数参数或者关键的其中一部分,生成一个简化了参数传入的新的函数对象。
例子:

from functools import partial

basetwo = partial(int, base=2)
print(basetwo(‘111‘))

5. functools.partialmethod(func, *args, **keywords)
功能与partial类似,用法如下:

    from functools import partialmethod

    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()
    print(c.alive)
    c.set_alive()
    print(c.alive)

  

6. reduce(function, iterable[,initializer])
将两个参数的函数从左到右累计应用于序列项,比如reduce(lambda x, y:x+y, [1, 2, 3, 4, 5]),相当于计算(((1+2)+3)+4)+5。

    from functools import reduce
    print(reduce(lambda x, y: x+y, range(0, 10)))

  

7. @functools.singledispatch
当有一个函数需要根据传入的变量的类型来判断需要输出的内容时,通常的做法是在函数内部使用大量的if/elif/else来解决问题。
这样做会使代码显得笨重,难以维护,也不便于扩展。
functools.singledispatch方法就是用于处理这个问题的

用法:

    from functools import singledispatch

    @singledispatch
    def func(arg, verbose=False):
        if verbose:
            print("Let me just say,", end=" ")
        print(arg)

    @func.register(int)
    def _(arg, verbose=False):
        if verbose:
            print("Strength in numbers, eh?", end=" ")
        print(arg)

    @func.register(list)
    def _(arg, verbose=False):
        if verbose:
            print("Enumerate this:")
        for i, elem in enumerate(arg):
            print(i, elem)

    def nothing(arg, verbose=False):
        print("Nothing.")

    func.register(type(None), nothing)

    @func.register(float)
    def fun_num(arg, verbose=False):
        if verbose:
            print("Half of your number:", end=" ")
        print(arg / 2)

    func("Hello, world.")
    func("test.", verbose=True)
    func(42, verbose=True)
    func(["spam", "spam", "eggs", "spam"], verbose=True)
    func(None)
    func(1.23)

    # 检查泛型函数将为给定类型选择哪个实现
    print(func.dispatch(float))
    print(func.dispatch(dict))

    # 访问所有已经注册的实现
    print(func.registry.keys())
    print(func.registry[float])

  

8. functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
用来更新被装饰函数的__name__,__doc__等信息,使其看起来像被装饰的函数

    from functools import update_wrapper

    def wrap(func):
        def call_it(*args, **kwargs):
            """call it"""
            return func(*args, **kwargs)
        return call_it

    @wrap
    def hello():
        """say hello"""
        print("hello world")

    def wrap2(func):
        def call_it2(*args, **kwargs):
            """call it2"""
            return func(*args, **kwargs)
        return update_wrapper(call_it2, func)

    @wrap2
    def hello2():
        """say hello2"""
        print("hello world2")

    print(hello.__name__)
    print(hello.__doc__)

    print(hello2.__name__)
    print(hello2.__doc__)

  

9. @functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
使用了wraps的装饰器可以保留被装饰函数的属性

    from functools import wraps

    def my_decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            print("Calling decorated function")
            return f(*args, **kwargs)
        return wrapper

    @my_decorator
    def example():
        """Example Docstring"""
        print("Called example function")

    example()
    print(example.__name__)
    print(example.__doc__)

  

文章中的例子来自Python官方文档和网络。

原文地址:https://www.cnblogs.com/hufulinblog/p/11251996.html

时间: 2024-11-12 21:49:56

Python标准库: functools (cmp_to_key, lru_cache, total_ordering, partial, partialmethod, reduce, singledispatch, update_wrapper, wraps)的相关文章

Python标准库--functools模块

functools模块:管理函数的工具 partial对象:包装原函数,提供默认值 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): print(name) pri

python标准库--functools.partial

官方相关地址:https://docs.python.org/3.6/library/functools.html 一.简单介绍: functools模块用于高阶函数:作用于或返回其他函数的函数.一般而言,任何可调用对象都可以作为本模块用途的函数来处理. functools.partial返回的是一个可调用的partial对象,使用方法是partial(func,*args,**kw),func是必须要传入的,而且至少需要一个args或是kw参数. 创建一个功能函数,实现三个数的相加,如果其中的

python 装饰器及标准库functools中的wraps

最近在看 flask的视图装饰器 时,忽然想起预(复)习一下python的装饰器. 这里有一篇比较好的讲解装饰器的书写的 Python装饰器学习(九步入门) . 这里不单独记录装饰器的书写格式了,重点是工作流程. 首先常见的 装饰器 格式就是通过@语法糖,简便的写法,让流程有些不太清楚. 装饰器不带参数的情况下: def deco(func):     def _deco():         print("before myfunc() called.")         func(

Python标准库(机器汉化)

Python标准库 虽然"Python语言参考"描述了Python语言的确切语法和语义,但该库参考手册描述了使用Python分发的标准库.它还介绍了Python发行版中通常包含的一些可选组件. Python的标准库非常广泛,提供了下面列出的长表所示的各种设施.该库包含内置模块(用C语言编写),提供对Python程序员无法访问的系统功能(如文件I / O)的访问,以及使用Python编写的模块,为出现的许多问题提供标准化的解决方案日常编程.其中一些模块是明确设计的,通过将特定平台抽象为平

Python 标准库一览(Python进阶学习)

转自:http://blog.csdn.net/jurbo/article/details/52334345 写这个的起因是,还是因为在做Python challenge的时候,有的时候想解决问题,连应该用哪个类库都不知道,还要去百度(我不信就我一个人那么尴尬TvT) 好像自从学习了基础的Python 语法,看了几本Python经典的书,知道了一些常见的类库.在几本语法应用熟练的情况下,如果不做题,像是无法显著的提高自己的知识储备了(所以叫你去做python challenge啊,什么都不会~~

python标准库Beautiful Soup与MongoDb爬喜马拉雅电台的总结

Beautiful Soup标准库是一个可以从HTML/XML文件中提取数据的Python库,它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式,Beautiful Soup将会节省数小时的工作时间.pymongo标准库是MongoDb NoSql数据库与python语言之间的桥梁,通过pymongo将数据保存到MongoDb中.结合使用这两者来爬去喜马拉雅电台的数据... Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是

Python标准库 (pickle包,cPickle包)

在之前对Python对象的介绍中 (面向对象的基本概念,面向对象的进一步拓展),我提到过Python"一切皆对象"的哲学,在Python中,无论是变量还是函数,都是一个对象.当Python运行时,对象存储在内存中,随时等待系统的调用.然而,内存里的数据会随着计算机关机和消失,如何将对象保存到文件,并储存在硬盘上呢? 计算机的内存中存储的是二进制的序列 (当然,在Linux眼中,是文本流).我们可以直接将某个对象所对应位置的数据抓取下来,转换成文本流 (这个过程叫做serialize),

Python标准库14 数据库 (sqlite3)

Python标准库14 数据库 (sqlite3) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Python自带一个轻量级的关系型数据库SQLite.这一数据库使用SQL语言.SQLite作为后端数据库,可以搭配Python建网站,或者制作有数据存储需求的工具.SQLite还在其它领域有广泛的应用,比如HTML5和移动端.Python标准库中的sqlite3提供该数据库的接口. 我将创建一个简单的关系型数据库,为一个书店存

【python标准库学习】thread,threading(二)多线程同步

继上一篇介绍了python的多线程和基本用法.也说到了python中多线程中的同步锁,这篇就来看看python中的多线程同步问题. 有时候很多个线程同时对一个资源进行修改,这个时候就容易发生错误,看看这个最简单的程序: import thread, time count = 0 def addCount(): global count for i in range(100000): count += 1 for i in range(10): thread.start_new_thread(ad