一.闭包
闭包函数:声明在一个函数中的函数,叫做闭包函数。
闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
想在全局情况下调用“全局函数”内部定义的函数,就必须令该全局函数返回“内部函数”的内存地址,然后将该内存地址赋值给一个变量,通过调用这个变量来实现“全局调用内部函数”,而此时,这个“内部的函数”就称为“闭包”。
# f2即为闭包
def f1():
n=999
def f2():
print(n)
return f2
result = f1()
result()
# f2即为闭包
闭包的作用
- 定义:闭包就是能够读取外部函数内的变量的函数。(前面已经讲解过)
- 作用1:闭包是将外层函数内的局部变量和外层函数的外部连接起来的一座桥梁。
- 作用2:将外层函数的变量持久地保存在内存中。
- 参考:Python闭包(Closure)详解 - 知乎
二.python中的装饰器
#!/usr/bin/python
import time
def outter(func):
def inner(*args,**kwargs):
start_time = time.time()
re = func(args[0])
end_time = time.time()
spend_time = end_time - start_time
return({'spend_time':spend_time,'result':re})
return inner
@outter #等价于test = outter(test)
def test(x):
time.sleep(5)
return 'test'+str(x)
x = test(2)
print(x)
》》》{'spend_time': 5.004472970962524, 'result': 'test2'}
因为:test = outter(test)
所以:test(2) = outter(test)(2)
所以当装饰器要带参数时,装饰器定时时需要再加一层外部函数 成为三层嵌套函数
装饰器运行时间:
被装饰器装饰的函数名即使没有被调用(因为有@xxx,会触发运行装饰器),(装饰器工厂函数)定义装饰器的代码已经运行了(最内部的那个函数并没有运行)(把被装饰的原函数引用赋值给了装饰器内部的那个函数名),当下边通过该函数名调用时,会调用到装饰器内部的那个函数()
三层方法示例
def logging_function_doc(logger):
"""记录被调用方法的 doc"""
def outter(func):
@wraps(func)
def inner(*args, **kwargs):
if func.__doc__: logger.info("doc: " + func.__doc__)
re = func(*args, **kwargs)
return re
return inner
return outter
调用:
@logging_function_doc(logger_obj)
def test_1(p1,p2):
print('test')
return 1
通过使用方式可以看出,生效原理与上面二层方法一致 只是多传入参数可供内部方法使用,@logging_function_doc(logger_obj)返回了outter方法,
三.使用小技巧
3.1 wraps在装饰器中的作用
Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring。
不加wraps:
# -*- coding=utf-8 -*-
from functools import wraps
def my_decorator(func):
def wrapper(*args, **kwargs):
'''decorator'''
print('Calling decorated function...')
return func(*args, **kwargs)
return wrapper
@my_decorator
def example():
"""Docstring"""
print('Called example function')
print(example.__name__, example.__doc__)
>>>
('wrapper', 'decorator')
加wraps:
# -*- coding=utf-8 -*-
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
'''decorator'''
print('Calling decorated function...')
return func(*args, **kwargs)
return wrapper
@my_decorator
def example():
"""Docstring"""
print('Called example function')
print(example.__name__, example.__doc__)
>>
('example', 'Docstring')
tips:
__name__: 执行当前文件时__name__ = ‘__main__’;被调用时:__name__ = 模块名
__doc__: 当前 文件/类/函数 的描述