一、闭包
定义:内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数
nonlocal关键字:如果想要在内函数中修改外函数的值,需要使用 nonlocal 关键字声明变量(见例子6)
判断是否为闭包:print( 内层函数名.__closure__ ) 结果为cell说明为闭包,结果为None说明不是闭包
注意:当程序执行遇到函数执行时,会在内存空间开辟局部命名空间,当函数执行完毕,该命名空间会被销毁。但是如果这个函数内部形成闭包,则该内存空间不会随着函数执行完毕而消失。
闭包的好处:当函数开始执行时,如果遇到了闭包,它有一个机制,它会永远开辟一个内存空间,将闭包中的变量等值放入其中,不会随着函数的执行完毕而消失。
闭包函数伪代码:
def 外层函数(参数):
def 内层函数():
print("内层函数执行:",参数)
return 内层函数
内层函数的引用 = 外层函数("传入参数")
内层函数的引用()
注意:
外层函数中的参数不一定存在,根据情况而定,
但是一般情况下都会有并在内层函数中使用到。
举例:
例子1:
def wrapper():
name = 'summer'
def inner():
print(name)
inner()
print(inner.__closure__)
wrapper()
执行输出:
summer
(<cell at 0x0000017FC9C90B58: str object at 0x0000017FCA349AD0>,)
例子2:函数调用了外层变量而非全局变量,那么它就是闭包。
name = 'summer'
def wrapper():
def inner():
print(name)
inner()
print(inner.__closure__)
wrapper()
结果输出:
summer
None
例子3:只要引用了外层变量至少一次,非全局的,它就是闭包
name = 'summer'
def wrapper2():
name1 = 'spring'
def inner():
print(name)
print(name1)
inner()
print(inner.__closure__)
wrapper2()
结果输出:
summer
spring
(<cell at 0x030B7310: str object at 0x03043680>,)
例子4:
虽然wraaper2传了一个全局变量,
但是在函数wraaper2内部,inner引用了外层变量,
相当于在函数inner外层定义了 n = 'summer',
所以inner是一个闭包函数。
name = 'summer'
def wraaper2(n): #相当于n = 'summer'
def inner():
print(n)
inner()
print(inner.__closure__)
wraaper2(name)
结果输出:
summer
(<cell at 0x03867350: str object at 0x037F3680>,)
例子5:
def func(a, b):
def line(x):
return a * x - b
return line
line = func(2, 3)
print(line(5))
结果输出:
7
例子6:nonclocal关键字声明变量!
def func(a, b):
def line(x):
nonlocal a
a = 3
return a * x - b
return line
line = func(2, 3)
print(line(5))
结果输出:
12
例子7:传如函数
import time
def timmer(f):
def inner():
start_time = time.time()
print('1')
f()
print('2')
end_time = time.time()
print("此函数的执行时间为:",str(end_time - start_time))
return inner
def func1():
print("in func1")
time.sleep(1)
func12 = timmer(func1)
func12()
结果输出:
1
in func1
2
此函数的执行时间为: 1.0986361503601074
二、装饰器 decorator
本质:本质是函数,用 def 定义。
基于类实现的装饰器:
(1)不带参数的类装饰器:必须实现__call__ 和__init__ 这两个内置函数。(例子4)
__init__: 接收被装饰函数 ; __call__ : 实现装饰逻辑。
(2)带参数的类装饰器:必须实现__call__ 和__init__ 这两个内置函数。(例子5)
__init__: 不再接收被装饰函数,而是接收传入参数 ; __call__ :接收被装饰函数, 实现装饰逻辑。
功能:装饰其他函数,即为其他函数添加附加功能。
原则:不能修改被装饰的函数的源代码、调用方式、执行结果。即:装饰器对待被修饰的函数是完全透明的。
必须满足的条件:闭包、外部函数的返回值必须是内部函数。
应用场景:插入日志、性能测试、事务处理、缓存....
functools.wraps装饰器:作用就是将被修饰的函数的一些属性值赋值给修饰器函数,最终让属性的显示更符合我们的直觉。(例子6 例子7)
内置装饰器 property:通常存在与类中,可以将一个函数定义成一个属性,属性的值就是该函数的return的内容。同时会将这函数变成另外一个装饰器。私有属性添加@XXX.setter 、@XXX.deleter方法(例子8)
例子:
例子1:日志打印器
def logger(func):
def wrapper(*args, **kwargs):
print('我准备开始计算:{}函数了'.format(func.__name__))
#真正执行的是这行
func(*args, **kwargs)
print('哈哈,我计算完啦。给自己加个鸡腿!')
return wrapper
@logger
def add(x, y):
print('{}+{}={}'.format(x, y, x+y))
add(100, 100)
输出结果:
我准备开始计算:add函数了
100+100=200
哈哈,我计算完啦。给自己加个鸡腿!
例子2:时间计时器--计算函数执行时长
import time
def timer(func):
def wrapper(*args, **kwargs):
t1 = time.time()
# 这是函数真正执行的地方
func(*args, **kwargs)
t2 = time.time()
print('花费时长:{}秒'.format(t2-t1))
return wrapper
@timer
def want_sleep(sleep_time):
time.sleep(sleep_time)
want_sleep(10)
输出结果:
花费时长:10.000004291534424秒
例子3:带参数的函数装饰器 --- 多一层嵌套传参即可!
def say_hello(country):
def wrapper(func):
def deco(*args, **kwargs):
if country == 'China':
print('你好!')
elif country == 'america':
print('hello!')
else:
return
#真正执行函数的地方
func(*args, **kwargs)
return deco
return wrapper
@say_hello('China')
def chinese():
print('我来自中国!')
@say_hello('america')
def america():
print('I am from America!')
america()
print('------------')
chinese()
结果输出:
hello!
I am from America!
------------
你好!
我来自中国!
---------------------------------------------------------------------------------------
例子4:不带参数的类装饰器
class logger():
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")
输出结果:
[INFO]:the function say() is running...
say hello
例子5:带参数的类装饰器
class logger():
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")
结果输出:
[WARNING]:the function say() is running...
say hello
---------------------------------------------------------------------------------------
例子6:
def wrapper(func):
def inner_function():
pass
return inner_function
@wrapper
def wrapped():
pass
print(wrapped.__name__)
输出结果:
inner_function
例子7:
from functools import wraps
def wrapper(func):
@wraps(func)
def inner_function():
pass
return inner_function
@wrapper
def wrapped():
pass
print(wrapped.__name__)
输出结果:
wrapped
----------------------------------------------------------------------------------
例子8: @property内置装饰器应用
class Student(object):
def __init__(self, name):
self.name = name
self.name = None
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if not isinstance(value, int):
raise ValueError('输入不合法:年龄必须为数值!')
if not 0 < value < 100:
raise ValueError('输入不合法:年龄范围必须0-100')
self._age=value
@age.deleter
def age(self):
del self._age
XiaoMing = Student("小明")
# 设置属性
XiaoMing.age = 25
# 查询属性
XiaoMing.age
# 删除属性
del XiaoMing.age