闭包和装饰器 嗨,周六中秋补班,是不是在期待假期呢?然而有些人请假了,觉得很无聊,在家里写笔记了 话不多说,走起~
什么是闭包
一个能记住嵌套作用域变量值的函数,尽管作用域已经不存在。这种语言现象称之为闭包:
例如函数f1结束了,但是f2仍然能记住x=88;这种情况下,嵌套函数内部会用到外部的变量x。
什么是装饰器
python语言中,可将函数作为参数传入一个装饰函数,返回另外一个被装饰了的函数;在这个过程中我们对函数添加新的功能;装饰器本身是一个函数或者类;
在学习装饰器的时候,执行以下代码的结果,不是预期的那样,我怀疑自己写错了
import logging
def use_logging(func):
def wrapper():
logging.info("%s is running" % func.__name__)
return func
return wrapper
@use_logging
def foo():
print("This is foo")
foo()
执行的结果是 空,于是乎,开始调试代码。在网上找到了以下代码,原来内层的函数需要返回的是函数的调用; 另外,将上述代码return wrapper 改为 return wrapper(),也会返回报错;原因是@use_logging的语法糖,就是相当于foo = user_logging(foo)。 显然,当执行函数时,装饰器函数就已经调用wrapper函数了,相当于调用func(),此时会执行func,返回值为空;如果return wrapper(),则多了一次函数调用,空类型是无法调用的;报错如下: 所以正确的装饰器代码如下:
def use_logging(func):
def wrapper():
print("%s is running" % func.__name__)
return func()
return wrapper
@use_logging
def foo():
print("This is foo")
foo()
** 以下是带参数的装饰器:**
def use_logging(func):
def wrapper(name):
print("%s is running" % func.__name__)
print("decorate %s is running" % name)
return func(name)
return wrapper
@use_logging
def foo(name):
print("This is %s" % name)
foo(2)
带参数的装饰器,且函数的参数名称可以和内层函数的参数名称不一致:
def use_logging(func):
def wrapper(AGE):
print("%s is running" % func.__name__)
print("decorate %s is running" % AGE)
return func(AGE)
return wrapper
@use_logging
def foo(name):
print("This is %s" % name)
foo(2)
装饰器的执行顺序: 一个函数还可以同时定义多个装饰器,比如:
@a
@b
@c
def f ():
pass
它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于 f = a(b(c(f)))
例如
def a(func):
def wrapper():
print('iner %s is running' % a.__name__)
return func()
return wrapper
def b(func):
def wrapper():
print('iner %s is running' % b.__name__)
return func()
return wrapper
def c(func):
def wrapper():
print('iner %s is running' % c.__name__)
return func()
return wrapper
@b
@a
def foo():
print("foo is running")
foo()
执行结果为: iner b is running iner a is running foo is running
代码注释: 多层的装饰器,相当于foo = b(a(foo)) ,函数执行从外到里,装饰器自下而上;内层返回的是a的wrapper的引用,但是并未执行; b(wrapper_a)返回的是b的wrapper的引用,但是未执行;当执行foo()时,会执行b_wrapper,相当于执行b中的func(),此时b的func已经被装饰,即为wrapper_a。 相当于先打印a内的一句话,再执行原函数func(打印一句话)
另外,由于先调用装饰器a,在调用装饰器b,所以会先打印a中外层的语句;例如:
def a(func):
print("outer a")
def wrapper():
print('iner %s is running' % a.__name__)
return func()
return wrapper
def b(func):
print("outer b")
def wrapper():
print('iner %s is running' % b.__name__)
return func()
return wrapper
@b
@a
def foo():
print("foo is running")
foo()
执行结果就是: outer a outer b iner b is running iner a is running foo is running
装饰器的应用
装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。 概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。(此处转载 https://foofish.net/python-decorator.html - 理解 Python 装饰器看这一篇就够了)
|