python学习之闭包和装饰器
python学习 . 2020/04/16发布 . shanyonggang_web . 我要评论 . 238阅读

闭包和装饰器是python中比较难理解的概念,首先理解下闭包

闭包

主要参考文档:python闭包详解闭包通俗理解

其大致是:在函数内再定义一个函数,内部的函数里运用了外部函数的临时变量,并且外部函数的返回值是内部函数的引用。这样就构成了一个闭包,代码如下:

import time

def show(a):
    b = 10
    def in_show(d):
        c = a + b + d
        print(c)
    return in_show

if __name__ == "__main__":
    jj = show(5)
    jj(4)

执行结果:发现输出19,首先show()执行外部函数,jj(4)执行return返回的函数,所以最终结果为19

闭包问题:

闭包不能直接使用外部变量(对该变量进行修改)、需要通过nonlocal声明关键字变量,如下:

import time

def show(a):
    b = 10
    def in_show(d):
        nonlocal b
        b = b-3
        c = a + b + d
        print(c)
    return in_show

if __name__ == "__main__":
    jj = show(5)
    jj(4)

执行结果,为16

闭包不能使用循环变量,比如for循环中的i值,如下:

装饰器

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

参考文档:廖雪峰装饰器讲解详解python装饰器一文搞定python装饰器强烈推荐装饰器

装饰器的使用方法:

定义装饰器函数(可用类、偏函数实现);定义业务函数或类;通过@函数名加入装饰器

简答用法讲解:日志打印和计时

打印日志,如下:

def logger(func):
    def wrapper(*args,**kw):
        print('我要开始执行{}函数了.....'.format(func.__name__))
        func(*args,**kw)
        print('你定义的函数计算好了.....')
    return wrapper

@logger
def show(name):
    print('我是{}'.format(name))

show('hello')

计时器,如下:

import time

def logger(func):
    def wrapper(*args,**kw):
        print('我要开始执行{}函数了.....'.format(func.__name__))
        start_time = time.time()
        func(*args,**kw)
        end_time = time.time()
        print('总耗时:{}'.format(end_time-start_time))
        print('你定义的函数计算好了.....')
    return wrapper

@logger
def show(name):
    time.sleep(10)
    print('我是{}'.format(name))

show('hello')

带参数的装饰器,使用两层函数嵌套的形式,如下:

import time

def show_country(text):
    def decorator(func):
        def wrapper(*args,**kw):
            if text == 'china':
                print("你好!")
            elif text == "america":
                print('hello.')
            return func(*args,**kw)
        return wrapper
    return decorator
            

@show_country("china")
def chinese():
  print("我来自中国。")

@show_country("america")
def american():
  print("I am from America.")

chinese()
print('-'*30)
american()

不带参数的类装饰器,基于类装饰器的实现,必须实现 __call__ 和 __init__两个内置函数,如下:

class logger(object):
  def __init__(self, func):
    self.func = func

  def __call__(self, *args, **kwargs):
    print("[INFO]: the function {func}() is running...".format(func=self.func.__name__))
    return self.func(*args, **kwargs)

@logger
def say(something):
  print("say {}!".format(something))

say("hello")

带参数的类装饰器,如下:

class logger(object):
    def __init__(self, level='INFO'):
        self.level = level

    def __call__(self, func): # 接受函数
        def wrapper(*args, **kwargs):
            print("[{level}]: the function {func}() is running...".format(level=self.level, func=func.__name__))
            func(*args, **kwargs)
        return wrapper #返回函数

@logger(level='WARNING')
def say(something):
    print("say {}!".format(something))

say("hello")

 


  • 有疑问请在下方评论区留言,我会尽快回复。
  • Email私信我: 511248513@qq.com 或添加博主 微信
本文作者:shanyonggang_web
发布时间:2020年4月16日 15:03
许可协议: 署名-非商业性使用 4.0 国际许可协议
知识共享许可协议     转载请保留原文链接及作者
正在加载今日诗词....
您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请狠狠点击下面的


登录 后回复

当前暂无评论,点击登录来做第一个吃螃蟹的人吧!