Python 闭包和装饰器

1、闭包

维基百科的定义

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量(该函数内部绑定的符号),也要包括自由变量(在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。捕捉时对于值的处理可以是值拷贝,也可以是名称引用,这通常由语言设计者决定,也可能由用户自行指定(如C++)。

说人话

情景一:想要在函数外访问函数内部变量,通常是做不到的,例如

python 复制代码
def fun1():
	i = 10
	return
print(i)  # 会报错

怎么实现这个功能呢?可以在函数里面再嵌套一层函数,把第一层函数的内部变量变成第二层函数的外部变量。

python 复制代码
def outer():
	i = 10
	def inner():
		return i
	return inner

func1 = outer()  # 即 func1==inner
print(func1())  # 输出结果为10

因此内层函数对外层函数非全局变量的引用且外层函数返回内层函数的形式就构成 闭包

情景二:假设我们需要动态求解每日支出的平均数,第一天支出100元,第二天200元,第三天300元,要求每天求解一下之前所有支出的平均数,可以这样实现:

python 复制代码
a_llist = []

def average(expend)
	a_list.append(expend)
	return sum(a_list)/len(a_list)

print(average(100))
print(average(200))
a_list = []  # 此时数据很容易被篡改
print(average(300))

但这样有个问题,因为a_list是全局变量,在程序任何地方都可以被修改,因此不能很好保护数据安全性和完整性,那么我们就可以使用闭包的一个特性,绑定自由变量和内层函数。

python 复制代码
def outer():
	a_list = []
	def inner(expend):
		a_list.append(expend)
		return sum(a_list)/len(a_list)
	return inner
	
average = outer()
print(average(100))
print(average(200))
# a_list = []  此时数据不容易被篡改
print(average(300))

通过以上修改,变量a_list便可存在于内存之中并和函数average建立对应关系,即保护了数据安全(不容易被篡改)也保证可以在函数外部调用函数内部变量。

2、装饰器

装饰器是利用 闭包 特性实现的一个功能。假设我们现在有很多个功能性函数,我们想测试每个函数运行在时间,并在当前函数运行时进行提示,简单粗暴的方法是这样:

python 复制代码
import time


def func1():
	start_time = time.time()
	...
	end_time = time.time()
	print(end_time-start_time)
	return

def func2():
	start_time = time.time()
	...
	end_time = time.time()
	print(end_time-start_time)
	return

func1()
func2()
...

但其实这样非常费时费力,如果我们不想计算某个函数的时间,就不得不重新注释掉加上去的代码,因此在遇到这种需要在不改变原函数程序的基础上增加新功能的方法就需要用到装饰器。

python 复制代码
import time

def timeDecorate(func):
	def compute_time(*args, **kargs):  # *args和**kargs是函数可变参数
		start_time = time.time()
		func(*args, **kargs)  # 执行原函数功能
		end_time = time.time()
		print("time:", end_time-start_time)
	return compute_time

@timeDecorate
def func1():
	print("func1...")

@timeDecorate
def func2():
	print("func2...")
...

func1()
func2()
...

当然这只是对装饰器原理的简单理解,复杂的应用方法还有待补充。。。

相关推荐
xiao5kou4chang6kai4几秒前
Python-GEE遥感云大数据分析与可视化(如何建立基于云计算的森林监测预警系统)
python·数据分析·云计算·森林监测·森林管理
presenttttt8 分钟前
用Python和OpenCV从零搭建一个完整的双目视觉系统(四)
开发语言·python·opencv·计算机视觉
每日出拳老爷子14 分钟前
[C#] 使用TextBox换行失败的原因与解决方案:换用RichTextBox的实战经验
开发语言·c#
半桔17 分钟前
【Linux手册】从接口到管理:Linux文件系统的核心操作指南
android·java·linux·开发语言·面试·系统架构
nightunderblackcat26 分钟前
新手向:实现ATM模拟系统
java·开发语言·spring boot·spring cloud·tomcat·maven·intellij-idea
开开心心就好29 分钟前
电脑息屏工具,一键黑屏超方便
开发语言·javascript·电脑·scala·erlang·perl
笑衬人心。36 分钟前
Java 17 新特性笔记
java·开发语言·笔记
序属秋秋秋2 小时前
《C++初阶之内存管理》【内存分布 + operator new/delete + 定位new】
开发语言·c++·笔记·学习
木头左3 小时前
逻辑回归的Python实现与优化
python·算法·逻辑回归
ruan1145143 小时前
MySQL4种隔离级别
java·开发语言·mysql