181116-Python函数特性

文章目录
  1. 1. map
  2. 2. reduce
  3. 3. filter
  4. 4. sorted
  5. 5. 匿名函数 lambda
  6. 6. 装饰器
  • II. 其他
    1. 1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
    2. 2. 声明
    3. 3. 扫描关注
  • 本篇博文主要介绍一些高级的函数特性,如map,reduce,filter,sort,装饰器,lambda等

    1. map

    这个map是指map/reduce中的map,而不是类似jdk的map数据结构

    在python中,map接收两个参数,第一个为函数,第二个为一个可迭代的对象,作用是顺序的将迭代器中的元素丢给函数执行,并将结果作为新的Iterator返回

    如将列表中的每个数求平方

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 列表生成式的写法
    >>> [ x*x for x in range(1,6)]
    [1, 4, 9, 16, 25]

    # 使用map的方法
    >>> def f(x):
    ... return x * x
    ...
    >>> list(map(f, range(1,6)))
    [1, 4, 9, 16, 25]

    上面这样对比之后,发现列表生成式的写法更加简洁,并不能凸显map的优越性

    换一个例子,将奇数采用*2,偶数采用平方的方式,则用列表生成式不太好写了

    1
    2
    3
    4
    5
    6
    7
    8
    >>> def f(x):
    ... if(x % 2==0) :
    ... return x * x
    ... else:
    ... return x *2
    ...
    >>> list(map(f, range(1,6)))
    [2, 4, 6, 16, 10]

    2. reduce

    map相当于是顺序的执行迭代器中的元素;而reduce则是每个元素执行完毕之后,会与下一个元素一起进行计算,最终返回的是函数最终的计算结果

    一个典型的case如,获取列表中元素的和

    1
    2
    3
    4
    5
    6
    7
    # 首先是导入依赖
    >>> from functools import reduce
    >>> def f(x, y):
    ... return x + y
    ...
    >>> reduce(f, range(1, 100))
    4950

    需要额外注意的是使用reduce需要引入对应的包

    3. filter

    过滤,同样接收两个参数,第一个为过滤函数(返回True/False,True表示保留);第二个为可迭代的对象

    如过滤数组中的所有偶数,只保留奇数

    1
    2
    3
    4
    5
    >>> def f(s):
    ... return s % 2 == 1
    ...
    >>> list(filter(f, range(1, 10)))
    [1, 3, 5, 7, 9]

    4. sorted

    sorted函数可以实现针对列表的排序,也可以接收一个key函数来实现自定义的排序,如按照绝对值大小进行排序

    1
    2
    3
    >>> l=[36, 5, -12, 9, -21]
    >>> sorted(l, key=abs)
    [5, 9, -12, -21, 36]

    5. 匿名函数 lambda

    使用lambda来修饰匿名函数,一般就是一个表达式,配合map/reduce等函数使用时,可能会非常简洁

    语法

    lambda 参数: 执行逻辑

    如针对列表中,每个数求平方后得出新的列表

    1
    2
    >>> list(map(lambda x: x*x, range(1, 5)))
    [1, 4, 9, 16]

    将前面的求和进行改造

    1
    2
    >>> reduce(lambda x,y:x+y, range(1, 100))
    4950

    6. 装饰器

    在python中这个装饰器的概念更加类似java中的代理模式,可以增强函数的某些操作,在实际使用中,和我们通常说的切面比较像

    因为在python中函数可以作为变量来传参使用,因此装饰器模式的实质就是包装一下需要执行的方法,然后在这个方法执行前后做一些事情

    实例1:

    通过装饰器模式来统计方法的执行耗时

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    import functools
    import time

    ## 统计方法执行时间
    print('----------------------- time start -----------------')


    def metric(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
    start = time.time()
    try:
    return func(*args, **kw)
    finally:
    end = time.time()
    print('%s() execute cost: %f() s' % (func.__name__, (end - start)))

    return wrapper


    @metric
    def timeCal():
    try:
    print('time cal now!')
    time.sleep(1)
    except InterruptedError as e:
    print(e)
    return 'hello world'


    print('res', timeCal())

    try:
    time.sleep(2)
    except InterruptedError as e:
    print(e)

    print('----------------------- time over -----------------')

    看下上面的metric方法,就是具体的装饰器实现方式,在需要引用的函数上面加上 @metric 即可了;需要额外注意的是在metric函数内部的wrapper函数上,多加了一行`@functools.wraps(func),主要是针对直接使用metric(timeCall)的调用方式时,返回的函数的签名依然为timeCall`,具体相关逻辑,参考: python教程之装饰器

    上面执行结果的输出如下

    1
    2
    3
    4
    5
    ----------------------- time start -----------------
    time cal now!
    timeCal() execute cost: 1.004160() ms
    res hello world
    ----------------------- time over -----------------

    实例2:

    打印函数执行的日志(如常见的提供rpc服务,输出函数执行时的请求参数和返回结果), 我们现在考虑这个装饰器可以自主选择是否传参的case

    看下面装饰器的具体实现中,首先是判断logger参数,如果是函数方式,则表示注解上没有额外参数,因此返回的是 decorate(prefix);否则返回decorate,两者之间的区别就是一个传参层级的问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    ## logger 方法

    print('----------------------- logger start -----------------')


    def logger(prefix):
    def decorate(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
    if not hasattr(prefix, '__call__'):
    print("prefix %s() req %s(), %s(): " % (prefix, args, kw))
    else:
    print("method %s() req %s(), %s(): " % (func.__name__, args, kw))

    return func(*args, **kw)

    return wrapper

    # 如果logger没有传参,则直接走if逻辑
    if hasattr(prefix, '__call__'):
    return decorate(prefix)
    else:
    return decorate


    @logger('selfCal')
    def selfCal():
    print('cal1....')


    @logger
    def selfCal2(text):
    print('cal2....', text)


    selfCal()
    selfCal2("2222")

    print('----------------------- logger end -----------------')

    II. 其他

    1. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

    一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

    2. 声明

    尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

    3. 扫描关注

    一灰灰blog

    QrCode

    知识星球

    goals

    评论

    Your browser is out-of-date!

    Update your browser to view this website correctly. Update my browser now

    ×