zoukankan      html  css  js  c++  java
  • python中的functools模块

    functools模块可以作用于所有的可以被调用的对象,包括函数 定义了__call__方法的类等

      1 functools.cmp_to_key(func)

        将比较函数(接受两个参数,通过比较两个参数的大小返回负值,0,或者正数)转换为key function(返回一个值用来比较或者排序的可调用对象),

        例如: sorted(iterable, functools.cmp_to_key(locale.strcoll))

    def cmp1(n1, n2):
        return n1 - n2
    
    
    a = [1, 6, 2, 9]
    print(sorted(a, key=functools.cmp_to_key(cmp1)))

      2 @functools.lru_cache(maxsize=128, typed=False)

        首先这是一个装饰器

        其次,介绍一下LRU算法:

          LRU是最常用的缓存算法,全称叫“Least Recently Used”,顾名思义,就是在缓存miss 并且缓存空间已满的时候,将最久没访问过的数据删除从而腾出空间。

        然后,说一下这个装饰器的两个参数的含义:

          maxsize: 表示缓存大小,如果设置为None,表示不限制,设置为0表示不启用缓存机制

          typed:如果设置为True,则该装饰器所装饰的函数的参数即使值相等(比如说 3 == 3.0 ),但类型不同(一个是整型一个是浮点),也会被区分对待为不同的缓存

        然后,说明一下这个装饰器对所装饰的函数的要求,

          1 函数的参数接收的值必须是不可变对象,像字符串,数字,元组等都属于此列 

          2 其次函数返回的对象最好也是不可变对象,当然这一点没有硬性要求,但是道理大家懂。

        来一个栗子:

    @functools.lru_cache(2526)
    def get_resource(page):
    
        url = "https://urls_does_not_contain_pornographic_informations/%s" % page
    
        try:
            with urllib.request.urlopen(url) as s:
                return s.read()
        except urllib.error.HTTPError:
            return 'Not Found'
    
    
    for i in range(1, 2526):
        pep = get_resource(i)
        print(pep)

      3 @functools.total_ordering

        首先这是一个类装饰器,这个类装饰器要求它所定义的类中必须定义:

          1  小于__lt__(), 小于等于__le__(),大于__gt__(),大于等于__ge__()中的一个

          2  还要定义等于__eq__()方法。

        只要我们按照要求定义了这些方法,该装饰器就会为我们完成其余的比较排序方法 。

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

         类似于这样:

    def abc(a, b):
        print a + b
    
    
    def partial(func, *args, **kwargs):
        args_li = list(args)
    
        def inner(*nargs, **nkwargs):
            args_li.extend(nargs)
            kwargs.update(nkwargs)
            return func(*args_li, **kwargs)
    
        return inner
    
    
    new_abc = partial(abc, 2)
    
    new_abc(4)

    实际上就是给某个函数加上几个固定参数然后返回一个新的函数,对于多个对象更新相同的值来说可以用到。比如:

    from functools import partial
    
    
    class Test(object):
        def __init__(self):
            self.name = "lala"
            self.age = 20
    
    
    def _update_attr(obj, update_dic):
        map(lambda item: setattr(obj, item[0], item[1]), update_dic.iteritems())
    
    
    update_attr = partial(_update_attr, update_dic={"name": "mncu", "age": 18})
    
    test_obj_list = [Test() for i in xrange(20)]
    
    map(update_attr, test_obj_list)
    
    for test_obj in test_obj_list:
        print test_obj.name, test_obj.age

       5 class functools.partialmethod(func, *args, **keywords)

        作用类似于上面的partial函数,但这个方法作用于类的方法,返回的是方法而不是函数

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

       6 functool.update_wrapper(wrapper, wrapped[, assigned][, updated])

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

        在python中,当一个函数被装饰器装饰后,这个函数名字对应的函数对象实际上是那个装饰器函数,也就是该函数名对应的的__name__以及__doc__实际上已经改变了,这就导致很难调试。而update_wrapper以及wraps就是用来解决这个问题。

    #!/usr/bin/env python
    # encoding: utf-8
    
    def wrap(func):
        def call_it(*args, **kwargs):
            """wrap func: call_it"""
            print 'before call'
            return func(*args, **kwargs)
        return call_it
    
    @wrap
    def hello():
        """say hello"""
        print 'hello world'
    
    from functools import update_wrapper
    def wrap2(func):
        def call_it(*args, **kwargs):
            """wrap func: call_it2"""
            print 'before call'
            return func(*args, **kwargs)
        return update_wrapper(call_it, func)
    
    @wrap2
    def hello2():
        """test hello"""
        print 'hello world2'
    
    if __name__ == '__main__':
        hello()
        print hello.__name__
        print hello.__doc__
    
        print
        hello2()
        print hello2.__name__
        print hello2.__doc__

    结果:

      before call
      hello world
      call_it
      wrap func: call_it

      before call
      hello world2
      hello2
      test hello

    from functools import wraps
    def wrap3(func):
        @wraps(func)
        def call_it(*args, **kwargs):
            """wrap func: call_it2"""
            print 'before call'
            return func(*args, **kwargs)
        return call_it
    
    @wrap3
    def hello3():
        """test hello 3"""
        print 'hello world3'

    结果:

      before call
      hello world3
      hello3
      test hello 3

    参考:

      https://blog.theerrorlog.com/simple-lru-cache-in-python-3.html, 作者: Kay Zheng  

      http://www.wklken.me/posts/2013/08/18/python-extra-functools.html  作者:WKLKEN 

  • 相关阅读:
    搜狗输入法赏析
    第二次冲刺个人总结05
    程序员的自我修养阅读笔记01
    第十五周学习总结
    mysql 查询优化
    mysql explain 详解
    nginx基本配置与参数说明
    input输入框实现联想关键词功能
    JS图片懒加载
    mysql中timestamp,datetime,int类型的区别与优劣
  • 原文地址:https://www.cnblogs.com/MnCu8261/p/8763552.html
Copyright © 2011-2022 走看看