函数式编程模块(二)、functools模块

2023-10-07 15:08:08 浏览数 (2)

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

1、functools.cmp_to_key(func)

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

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

代码语言:javascript复制
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 ),但类型不同(一个是整型一个是浮点),也会被区分对待为不同的缓存。然后,说明一下这个装饰器对所装饰的函数的要求,函数的参数接收的值必须是不可变对象,像字符串,数字,元组等都属于此列,其次函数返回的对象最好也是不可变对象,当然这一点没有硬性要求。

例:

代码语言:javascript复制
@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

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

小于__lt__(), 小于等于__le__(),大于__gt__(),大于等于__ge__()中的一个,还要定义等于__eq__()方法。只要我们按照要求定义了这些方法,该装饰器就会为我们完成其余的比较排序方法 。

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

类似于这样:

代码语言:javascript复制
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)

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

代码语言:javascript复制
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函数,但这个方法作用于类的方法,返回的是方法而不是函数。

代码语言:javascript复制
>>> 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就是用来解决这个问题。

代码语言:javascript复制
#!/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__


Output:
---------------------
  before call
  hello world
  call_it
  wrap func: call_it

  before call
  hello world2
  hello2
  test hello
---------------------
代码语言:javascript复制
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'


Output:
-------------------
before call
hello world3
hello3
test hello 3
-------------------

0 人点赞