Python3学习笔记(16)----python的装饰器和匿名函数

原创 2018年04月15日 20:52:46

1、匿名函数

当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。

在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算f(x)=x2时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:

>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]

通过对比可以看出,匿名函数lambda x: x * x实际上就是:

def f(x):
    return x * x

关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:

>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25

同样,也可以把匿名函数作为返回值返回,比如:

def build(x, y):
    return lambda: x * x + y * y

2、装饰器

函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数

>>> def now():
...     print('2015-3-25')
...
>>> f = now
>>> f()
2015-3-25

函数对象有一个__name__属性,可以拿到函数的名字:

>>> now.__name__
'now'
>>> f.__name__
'now'

现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:

@log
def now():
    print('2015-3-25')

调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:

>>> now()
call now():
2015-3-25

把@log放到now()函数的定义处,相当于执行了语句:

now = log(now)

由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

那为什么还会调用原来的函数呢?
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

这个3层嵌套的decorator用法如下:

@log('execute')
def now():
    print('2015-3-25')

执行结果如下:

>>> now()
execute now():
2015-3-25

和两层嵌套的decorator相比,3层嵌套的效果是这样的:

>>> now = log('execute')(now)

我们来剖析上面的语句,首先执行log(‘execute’),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。

以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有name等属性,但你去看经过decorator装饰之后的函数,它们的name已经从原来的’now’变成了’wrapper’:

>>> now.__name__
'wrapper'

因为返回的那个wrapper()函数名字就是’wrapper’,所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

或者针对带参数的decorator:

import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
版权声明:可转载,记得写明原地址 https://blog.csdn.net/jin970505/article/details/79953121

足球与编程

  我是一个很容易满足很容易快乐很容易感动的人, 但每每看了中国猪球队的比赛, 就好象换了另一个人,连GF都不敢靠近, 我一直在思考中国猪球队的队员们为什么总是这样, 没有激情没有精神没有骨气,到底是...
  • harrymeng
  • harrymeng
  • 2003-09-11 11:13:00
  • 2208

Python3学习(24)--内置装饰器@property

@property 前面我们学过装饰器,我们知道,装饰器的作用就是用来扩展函数的,当然前面我们介绍的装饰器,都是我们自己定义的,格式如下: @decoretor def func(*args,**...
  • Appleyk
  • Appleyk
  • 2017-09-05 12:40:51
  • 3725

Python3.5——装饰器及应用详解(上)

1、装饰器: (1)本质:装饰器的本质是函数,其基本语法都是用关键字def去定义的。 (2)功能:装饰其他函数,即:为其他函数添加附加功能。 (3)原则:不能修改被装饰的函数的源代码,不能修改被装饰的...
  • loveliuzz
  • loveliuzz
  • 2017-09-05 21:15:48
  • 470

Python3 装饰器

Python3 装饰器 装饰器: 本质是函数, 用于装饰其他函数, 附加一些本身所没有的功能...
  • Rozol
  • Rozol
  • 2017-05-04 21:58:21
  • 2283

python3.3 装饰器日志

#!/usr/local/bin/Python3.3 #-*-coding:utf-8-*- def log_none_params(func): ''' none params decorat...
  • zhang_Red
  • zhang_Red
  • 2013-06-05 13:39:56
  • 1662

python3学习笔记:装饰器

想理解Python的decorator首先要知道在Python中函数也是一个对象,所以你可以将函数复制给变量 将函数当做参数 返回一个函数函数在Python中给变量的用法一样也是一等公民,也就是高阶函...
  • xionghuixionghui
  • xionghuixionghui
  • 2017-03-23 13:25:48
  • 1261

Python匿名函数详解

文章导读: 以前自己一直没搞明白Python中的匿名函数,现在拿这个问题基本上搞明白了,拿自己的理解整成一篇文章,附带大量例子,让其更加好理解。 ------- 在编程语言中,函数的应用: 1. 代...
  • Jerry_1126
  • Jerry_1126
  • 2014-10-15 12:54:27
  • 4781

Python3之迭代器对象,函数,匿名函数

迭代是Python最强大的功能之一,是访问集合元素的一种方式。。 迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。...
  • wqewq19
  • wqewq19
  • 2016-11-18 11:29:00
  • 389

Python装饰器单例

python装饰器实现单例
  • dutsoft
  • dutsoft
  • 2016-07-28 18:48:38
  • 599
收藏助手
不良信息举报
您举报文章:Python3学习笔记(16)----python的装饰器和匿名函数
举报原因:
原因补充:

(最多只允许输入30个字)