python闭包和装饰器

    要理解装饰器,就要明白闭包;
    要明白闭包,首先就要从高阶函数和作用域说起;

1、作用域

说道作用域,一般会谈到LEGB规则。所谓的LEGB:

L:locals,当前命名空间(局部作用域)
E:enclosing,外部函数的命名空间(外部作用域)
G:global,全局的命名空间
B:bulit in,内建的命名空间

平常的变量命名并赋值如

 x=4
 def f():
     print(x)
     
 print(x)#正确运行
 f()#错误

则x是一个局部的变量,只有在同一作用域的代码块才能调用到x。直接打印x的值是可以的。但是通过调用f来打印是不能的,因为其中的x是形参,并没有指向内存中的单元。也就是方法f中的x不在同一个作用域。


但是,如果在方法f中用global声明变量x

x = 4
def f():
    global x
    print(x)
f()

通过这样的方式,将方法x声明为全局变量,则方法中变量x的就是方法外的变量x。
而内建的命名空间,就是python默认支持的函数,也称为内建函数,比如说:

abs()#求绝对值
add()#两数相加
sum()#求和

调用这些方法不需要提前声明,可以直接使用。而外部作用域,一般是用在闭包中的,谈到闭包,还要讲一讲高阶函数。


2、高阶函数

高阶函数有两个特点:

1、函数名能够作为参数传递到到函数的内部
2、函数名能够作为返回值

也就是说,我们能够把一个普通的函数作为参数,在另一个函数体内返回,通过变量接收后调用来实现调用这个普通函数。

def f():
	print("haha")

def fn(f):#函数f通过参数传递到fn
	print("hehe")
	return f
b = fn()
b()

如此,fn就是一个高阶函数。f通过参数传递到fn的内部然后返回。当执行b=fn()时,print语句被执行,输出其中内容。而后返回了一个函数对象,用变量b接受函数对象后,就可以对b进行函数的调用了。


3、函数的嵌套(闭包)

函数是可以进行嵌套创建的:

def fn():
	x = 4
	def f():
		print(x)
	return f
a = fn()
a()

函数的嵌套其实没啥好说的,关键是其中的x的作用域问题。在函数f的函数体里面,并没有声明变量x,也没有传参,为什么能够取到x的值?
这也就是上面说的LEGB规则了。当执行print时,首先查找当前的局部作用域,发现没有找到符合的,于是就去外部作用域找。变量x处于的正是外部作用域。如果在外部作用域还找不到,就去全局作用域中找,再找不到,就去内建作用域中找。内建作用域中找不早,就会报错。

那么,问题来了!!

当执行函数fn()时,只有执行了return 语句,函数f并没有被调用。也就是说,调用函数a()才是对函数f的调用,换一个角度,函数f是在外面的执行的,但是当执行了函数fn后,变量x的内容已经被清空了,那么在外面调用函数f时为什么能够取到变量x的值呢?

这就是涉及到的闭包了。函数fn里return的函数f就是一个闭包函数。

闭包的定义:如果在一个内部函数里,对在外部作用域的变量进行引用,那么内部函数就被认为是闭包。

所以说,闭包是函数的定义加上定义时的环境。


4、装饰器

如果你要对已经提交的成品代码的某些函数添加功能,或者对多个函数添加相同的功能,你会怎么做?
如果直接修改源代码,那么就会对某些调用该函数的代码产生影响。如果该代码已经被运行,修改代码就会产生错误,导致软件停止运行。在实际生产是很要命的。
我们一步一步思考。

1、首先,可以利用高阶函数的特性,你可以选择创建一个函数,然后在该函数体内调用功能函数,然后用功能函数相同的变量接收。

def func(f):
	def fn():
		print("yingyingying")
		f()#调用的功能函数
	return f

f = func()
f()

从原功能函数来讲,函数func就是一个装饰函数,对函数f进行了装饰。Python提供了一种语法来进行这样的装饰行为,就是装饰器

def func(f):
	def fn():
		print("yingyingying")
		f()
	return fn()

@func
def f():
	#功能代码
	
f()

其中,@func就是声明装饰器函数,它的意义就是同上面的 f = func(),它的作用就是将功能函数中的代码转移到函数func中执行。若功能函数f带参数,则在装饰器函数中的fn中传递功能函数所需的参数。

2、带参数的装饰器
如果装饰器函数需要参数,怎么办呢?那么,就要用到闭包了。

def func_decorate(x):
	def func(f):
		def fn():
			print("yingyingying")
			print(x)
		return fn
	return func

@func_decorate(3)
def f():
	#功能代码

f()

其中的关键:

1、保存外部变量x,返回闭包函数func
2、f = func()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值