Python中闭包和装饰器的学习攻略
作者:颂love
一、闭包
(1)作用域
学习闭包前先要回顾一下作用域的知识:作用域一般分为全局作用域和局部作用域,对应使用的就是全局变量和局部变量;
值得注意的是在局部作用域中可以访问全局变量,而全局作用域中是不能访问局部变量的
原因:Python的底层存在一个内存回收空间,用于加快计算机的运行;变量同样需要占用内存,当局部作用域所代表的函数在运行过后,其内部的变量和程序会被Python当作已经使用过的内存进行回收
既然是范围方面的程序就会有解决的方法,当程序中需要在全局作用域实现对局部变量的访问时,就要用到闭包了
(2)闭包的含义
闭包:在函数嵌套的前提下,内部的函数使用了外部函数的变量,外部函数又返回了内部函数,这时这个内部函数就是闭包
(3)闭包的构成
如何区分一个程序是否存在闭包,闭包一般有三步构成的条件:
1、存在函数的嵌套
2、有内部函数的对于外部函数的引用
3、有外部函数对内部函数进行返回(即return)
这里需要注意的是,闭包引用了外部函数的变量,所以外部函数的变量在运行完外部函数之后其内存并没有得到释放,会消耗内存
经典闭包的构成例子:
def outer():
num = 20
def inner():
print(num)
return inner
f = outer()
f()
1、存在嵌套函数:outer是外部函数,inner是内部函数
2、内部函数inner引用了外部函数outer中的自由变量num
3、外部函数outer返回了内部函数inner的引用
4、当outer()执行完毕后,返回的inner函数依然可以访问并保留对变量num的绑定,形成闭包
(4)闭包实现对外部变量的修改
这里要引用一个新的关键词nonlocal;它是用于声明函数内部修改函数外部的变量,这个变量不是全局变量
它和global关键字不同就在于global在函数内部声明变量,但这个变量是全局变量
二者在实际的使用是相似的,只是使用的场景和作用不同
闭包实现修改的案例:
def outer():
res = 20
def inner(num):
nonlocal res
res += num
print(res)
return inner
f = outer()
f(1)
f(2)
res作为外部函数的局部变量,num作为内部函数的变量;res+=num就能直接修改res变量,再打印res引用外部函数变量,outer()再返回内部函数inner形成闭包,最后全局使用外部函数,可以看到这时的f(1)和f(2)中res发生了变化,而且是递进改变的

二、装饰器
(1)什么是装饰器
装饰器:在不改变现有函数代码和函数调用的前提下,实现给函数增加额外的功能
装饰器本质上也是一个闭包函数
(2)装饰器的定义
def register(fn):
def inner():
print('开始注册')
fn()
return inner
@register
def login():
print('登录成功')
login()register就是一个装饰器函数,接收函数fn为参数;
@register语法就是将装饰器应用于login函数中
调用login时其实是调用了装饰器register中的inner函数,所以先打印开始注册,然后打印登录成功
效果如下:

(3)装饰器的简单使用
import time
def get_time(fn):
def inner():
start = time.time()
fn()
end = time.time()
print(f"执行时间为:{end - start}s")
return inner
@get_time
def demo():
for i in range(1000000):
print(i)
demo()这个装饰器功能用于可以计算下面demo()函数运行完的执行时间,感兴趣可以深入了解一下
(4)装饰器的形式(了解即可)
带参数的装饰器
def log(fn):
def inner(*args, **kwargs):
fn(*args, **kwargs)
return inner
@log
def demo_1(*args, **kwargs):
res = 0
for i in args:
res += i
for i in kwargs.values():
res += i
print(res)
demo_1(10, 20, a=30, b=40)
关于不定长参数,在之前的Python学习中已经了解了,这里不多阐述
带返回的装饰器
def log(fn):
def inner(*args, **kwargs):
return fn(*args, **kwargs)
return inner
@log
def demo_1(a, b):
res = a - b
return res
print(demo_1(20,10))
通用装饰器
def log(fn):
def inner(*args, **kwargs):
return fn(*args, **kwargs)
return inner
@log
def demo_1(a, b):
res = a + b
return res
print(demo_1(20,10))
@log
def demo_2(a, b, c):
res = a + b + c
return res
print(demo_2(20,10,5))
一般装饰器形式以这个为准
可以看到装饰器的形式一般都大差不差,按照闭包的形式遵循一定的规则,然后调用函数即可
(5)装饰器的扩展(了解)
使用装饰器传递参数
基本语法:
def 装饰器名(形参):
#代码
@装饰器名('参数')
def 被装饰函数():
#代码
代码:
def log(flag):
def f1(fn):
def inner(*args, **kwargs):
if flag == '+':
print("正进行加法运算")
elif flag == '-':
print("正进行减法运算")
return fn(*args, **kwargs)
return inner
return f1
@log('+')
def demo_1(a, b):
res = a + b
return res
@log('-')
def demo_2(a, b):
res = a - b
return res
print(demo_1(20,10))
print(demo_2(100,10))效果如下:

类装饰器
基本语法:
class 类装饰器():
#代码
@类装饰器名称
def 函数():
#代码代码:
class Check():
def __init__(self, fn):
self.__fn = fn
def __call__(self, *args, **kwargs):
print("开始检查")
self.__fn(*args, **kwargs)
@Check
def comment():
print("正在检查")
comment()效果如下:

其实就是在装饰器的基础上用到了类的方法
总结
到此这篇关于Python中闭包和装饰器学习攻略的文章就介绍到这了,更多相关Python闭包和装饰器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
