zoukankan      html  css  js  c++  java
  • 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官方文档和网络。

  • 相关阅读:
    docker常用命令
    2020/10/10,饮食男女-对教条主义的补充和现实的摸索
    2020/08/24,约束力
    2020/08/21,迷茫的时候就去工作
    2020/08/21,神秘和平易近人
    2020/08/21,圣人和教条
    2020/07/21,翡翠梦境
    2020/10/10,生活不是阶段式跳跃的,是螺旋式的。
    2020/07/23,再论point,way,moment,time
    2020/07/13,旅游的意义是什么
  • 原文地址:https://www.cnblogs.com/hufulinblog/p/11251996.html
Copyright © 2011-2022 走看看