zoukankan      html  css  js  c++  java
  • Python operator模块和functools模块

    Python 中的 operator 模块和 functools 模块主要用于函数式编程

    operator 模块

    1)算术运算符函数

    函数式编程中,经常需要把算术运算符当作函数使用,例如求阶乘

    使用 lambda 的例子

    from functools import reduce
    
    def fact(n):
        return reduce(lambda a, b: a * b, range(1, n+1))
    

    使用 operator 模块的例子
    from functools import reduce
    from operator import mul
    
    def fact(n):
        return reduce(mul, range(1, n+1))
    

    operator 模块位多个运算符提供了对应的函数,从而避免了写 lambda 表达式,形式上更简洁,类似的还有 add、sub 等函数


     
    2)itemgetter

    itemgetter 函数用于从序列中(根据索引)或者映射类型中(根据键)读取元素

    >>> from operator import itemgetter
    >>>
    >>>
    >>> a = ['h', 'e', 'l', 'l', 'o']
    >>> b = (2, 3, 4)
    >>> c = range(5)
    >>> f = itemgetter(1)  # 区索引为 1 位置的值
    >>> f(a)
    'e'
    >>> f(b)
    3
    >>> f(c)
    1
    
    >>> d = {'name': 'hhh', 'age': 18}
    >>> f = itemgetter('name')  # 取键为 name 的元素
    >>> f(d)
    'hhh'
    

    itemgetter 返回的是一个可调用对象,其参数是序列或者映射类型


    itemgetter 多用于作为高阶函数的参数

    >>> users = [{'name': '犬夜叉', 'age': 100}, {'name': '戈薇', 'age': 14}, {'name': '珊瑚', 'age': 20},{'name': '弥勒', 'age': 22}]
    >>> users.sort(key=itemgetter('age'))  # 按年龄排序
    >>> print(users)
    [{'name': '戈薇', 'age': 14}, {'name': '珊瑚', 'age': 20}, {'name': '弥勒', 'age': 22}, {'name': '犬夜叉', 'age': 100}]
    

    事实上,itemgetter 不仅支持序列和映射类型,还支持任何实现了 __getitem__ 方法的类

    如果 itemgetter 传入多个参数,返回的结果会是一个元组

    >>> a = [1, 2, 3, 4, 5]
    >>> f = itemgetter(0, -1)
    >>> f(a)
    (1, 5)
    


     
    3)attrgetter

    attrgetter 与 itemgetter 作用类似,它根据名称提取对象的属性

    >>> from collections import namedtuple
    >>> from operator import attrgetter
    >>> profile = namedtuple('Profile', ['name', 'age', 'hobby'])
    >>>
    >>> profile
    <class '__main__.Profile'>
    
    >>> quanyecha = profile(name='犬夜叉', age=100, hobby='坐下')
    >>> f = attrgetter('name', 'age')
    >>>
    >>> f(quanyecha)
    ('犬夜叉', 100)
    

    可以看到 attrgetter 跟 itemgetter 几乎一样,也可以传入多个参数获取元组

    attragettter 还可以传入带 . 的参数,attrgetter 会深入嵌套对象,获取指定的属性

    >>> profile = namedtuple('Profile', ['name', 'age', 'spouse'])
    >>>
    >>> gewei = profile(name='戈薇', age=14, spouse='犬夜叉')
    >>> quanyecha = profile(name='犬夜叉', age=100, spouse=gewei)
    >>>
    >>> get_spouse_name = attrgetter('spouse.name')
    >>> get_spouse_age = attrgetter('spouse.age')
    >>>
    >>> get_spouse_name(quanyecha)
    '戈薇'
    >>> get_spouse_age(quanyecha)
    14
    


     

    functools 模块

    functools 模块提供了一系列高阶函数,最常见的是 reduce ,除了 reduce ,还有 partial 函数比较有用

    1)reduce

    reduce 用于把某个操作连续运用到序列的元素上,累计之前的结果,把一系列归约成一个值

    >>> from functools import reduce
    >>> from operator import add
    >>> reduce(add, range(100))
    4950
    


     
    2)partial

    partial 用于部分应用一个函数,部分应用指基于一个函数创建一个新的可调用对象,把原函数的某些参数固定

    先来看一个简单的例子

    >>> from functools import partial
    >>> from operator import mul
    >>> from functools import partial
    >>> triple = partial(mul, 3)
    >>> triple(6)
    18
    >>> list(map(triple, range(1,10)))
    [3, 6, 9, 12, 15, 18, 21, 24, 27]
    
    >>> triple.func
    <built-in function mul>
    >>>
    >>> triple.args
    (3,)
    

    其中 mul 函数接收两个参数,partial(mul, 3) 返回一个可调用对象,把 mul 函数的第一个参数固定为 3,这样之后再调用这个可调用对象就只需要传入一个参数

    下面来看一个笔画排序的例子

    class Stroke:
        """汉字笔画排序"""
        @classmethod
        def get_stroke_order(cls, chars: str):
            """获取排序"""
            return tuple(cls.stroke.get(i, math.inf) for i in chars)
    
        @classmethod
        def compare(cls, a: tuple, b: tuple):
            for a_i, b_i in itertools.zip_longest(a, b, fillvalue=0):
                if a_i < b_i:
                    return -1
                elif a_i > b_i:
                    return 1
                else:
                    pass
            return 0
    
        @classmethod
        def compare_by_stroke(cls, x, y, key: Callable):
            a = key(x)
            b = key(y)
            return cls.compare(a, b)
    
        @classmethod
        def sort_by_stroke(cls, obj: Iterable, key: Callable):
            cmp = functools.partial(cls.compare_by_stroke, key=key)
            return sorted(obj, key=functools.cmp_to_key(cmp))
    

    Stroke 的使用方式为

    >>> pprint(p)
    [{'age': 19, 'name': '陈世美', 'score': 29},
    {'age': 18, 'name': '张大千', 'score': 27},
    {'age': 29, 'name': '林强', 'score': 34},
    {'age': 56, 'name': '王大志', 'score': 21},
    {'age': 34, 'name': '王大', 'score': 32},
    {'age': 67, 'name': '王大福', 'score': 13}]
    >>>
    >>> for i in p:
    ...     i['order'] = Stroke.get_stroke_order(i['name'])
    
    >>> q = Stroke.sort_by_stroke(p, lambda x: x['order'])
    

    上面的例子里把 cls.compare_by_stroke 函数的 key 参数固定住,返回一个可调用对象,再通过可调用对象作为 sorted 函数的 key 来排序


    个人认为 partial 函数的作用在于定制化,先写一个通用的函数,然后根据实际需要固定这个函数里的某些参数得到新的可调用对象

    补充说一下,上面的 cmp_to_key 是一种兼容的做法,Python3 不支持比较函数,再一些接受 key 的函数中(例如 sorted,sort,min,max),key 仅仅支持一个参数,就无法实现两个参数之间的比较,采用 cmp_to_key,可以接受两个参数,将两个参数做处理,转换成一个参数,就可以应用于 key 关键字之后

    >>> from functools import cmp_to_key
    >>> l = ['2', '3', '1', '10', 8]
    >>> sorted(l, key=cmp_to_key(lambda x,y:int(x)-int(y)))
    ['1', '2', '3', 8, '10']
    
  • 相关阅读:
    让Asp.NET的DataGrid可排序、可选择、可分页
    锁的一些概念
    我在delphi7下调用微软的Web Services的心得
    CRM 之 销售功能点分析[转]
    OFFICE InfoPath 教程
    Take me to your heartMichael Learns To Rock
    NetAdvantage(WebCombo)设置说明
    WebService小记
    Fading Like a Flower Roxette
    UndividedBon Jovi
  • 原文地址:https://www.cnblogs.com/zzliu/p/14223340.html
Copyright © 2011-2022 走看看