在开始学习之前,我们先来了解一下作用域的概念,接下来我们先来看下下面这段程序:
a = 0 # 定义了一个变量a
def func1(): # 定义了一个方法func1
a = 1 # 将变量赋值为1
func1() # 调用了方法func1
print(a) # 将变量a输出了
# 输出结果:
# 0
我们发现变量a并没有被修改,这是因为func1()方法中的a和方法外的a并不是同一个a,这就像是在电影院看电影,有很多的位置,每个位置都是单独的,你在位置上吃东西还是干嘛,跟其他人没有关系,只要别影响别人就行;在我们程序里面也是一样的,每一个方法都是一个独立的个体,在执行的时候才会存在内存中,当方法执行完毕了,就像是电影看完了,就要离场了,总不能一直占着位置,这样这块内存空间就会释放;
那么我们怎么在方法的内部调用外部的变量呢?这时候我们可以用global导入全局变量:
def func1():
global a
a = 1
这样就相当于是买了两张票和朋友一起去看电影,那么另一个位置的吃的喝的也能够享用了;那么这个就是作用域的概念,只有在我的合法空间内才能做我们想做的事情。
那么接下来,我们再看一段程序:
def func1():
print('func1 print')
def func2():
print('func2 print')
func2()
func1()
# 输出结果:
# func1 print
# func2 print
这种写法我们之前没有见过,在方法里面我们又定义了一个方法,并且在func1()中我们直接调用了func2(),那么问题来了,我们能不能直接在方法外部调用func2呢?
我们可以看见程序运行报错了,提示func2没有定义,那么问题来了,为什么func1可以正常运行,func2就有问题呢?
这是因为方法都是先定义,后使用的;func1()能够被调用,是因为我在上面定义过了;按理当我运行完func1()之后,func2()不是也应该被定义了嘛,但是请注意,上面说过了,当方法执行完毕之后,占用的内存空间是会被释放掉的,那么func2()在func1()执行完毕之后就被释放了,func2也将不存在了,下面调用一个不存在的东西,肯定会报错啊!!!
那么,如果我就是想用func2该怎么办呢?
我们发现,可以将func2 return出来呀,注意这里的func2指的是函数对象,func2()是方法的调用,当我通过调用func1()这个方法将func2返回给func之后,func就相当于把这个方法单独提出来了,这个方法的所有数据和效果,通过func都可以实现;
OK,这个如果可以理解的话,我们接下来就要开始讲什么是闭包了,还是先看一段程序:
def func1():
a = 1
def func2():
print(a)
return func2
func = func1()
func()
# 输出结果:
# 1
我们观察上面的程序和运行结果,发现好像有悖于我们上面的说法,a不是外部的变量,这里也没有通过global导入,我在func2()中怎么能直接使用呢?那么这只有一种可能,当func1()执行完毕后,所有的内容都消失,这是一定的,不然我们print(a)应该就有结果输出;那么这个a就只能被存放在了func中,我们来实验一下:
def func1(obj):
print(obj)
def func2():
obj[0] += 1
print(obj)
return func2
func = func1([0,1,2,3])
func()
func()
func()
# 输出结果:
# [0, 1, 2, 3]
# [1, 1, 2, 3]
# [2, 1, 2, 3]
# [3, 1, 2, 3]
我们通过外部传参,传进了一个列表,我们在func2中对列表的第一个数字进行了修改,我们发现后面连续的三个func(),这个列表还是存在的,这就说明了func不仅对func2()这个方法进行了存储,还对与他有关的变量进行了存储;
那么现在我们可以总结下,一个方法定义中引入了这个函数以外的变量,并且这个方法在脱离了其定义的环境下还可以被正常执行,这个函数就叫闭包函数。
OK,那么接下来我们就看下什么是装饰器?
def func(func):
def func1():
print('已经调用了装饰器:')
return func()
return func1()
@func
def func2():
print('func2 print')
# 已经调用了装饰器:
# func2 print
上面就是一个简单的装饰器的应用,我们可以先看一下效果:
- 第一行输出了:“已经调用了装饰器”,我们发现这段话是在func()中的func1()方法中输出的
- 第二行则是在func2()中输出的
我们发现这是两个半毛钱没有关系的方法,怎么就一起被执行调用了呢?而且我们也没有发现有任何调用的语句啊?还有一个奇怪的东西,@func是个什么东西?
细心的朋友可能发现了,@func貌似起到了一个承上启下的作用,它貌似是一个桥梁,将两个函数连接起来了,它就是装饰器的一个应用;我们接下来来看一下它到底做了些什么事情:
- 首先先输出了“已经调用了装饰器”,那么肯定执行了func1()中的内容,通过上面的学习,我们知道要想调用func1()肯定是:f = func() -> f(),那么我们合并一下就是:func()()
- 然后才是执行func2()的内容,我们发现func()方法是有一个参数的,通过函数体我们可以知道,这个参数其实就是一个函数对象,因为在func1()中被调用了
- 那么我们再来整理一下,就可以得到:func(func2)(),最后的一个执行过程也是这样的执行过程,那么这样就能解释上面的问题了;
这里还有一个问题,我在上面为什么要return func()呢?我直接func()不行吗?当然可以,但是需要注意的是,这种情况在没有返回值的时候可以直接这么写,如果有返回值的话,就缺少了返回返回值这一步;也就是说return func()其实是将func()这个方法的结果进行返回了;
最后我们思考一个问题,装饰器可以接受参数嘛?
def func(sta):
def func1(func_):
def func2():
if sta:
print('状态正常!')
else:
print('状态不正常!')
return func_()
return func2
return func1
@func(True)
def func_t():
print('机器正常运行!')
@func(False)
def func_f():
print('机器出现故障!')
func_t()
func_f()
当然可以,其实也是一样的道理,这里就不赘述了!
1万+

被折叠的 条评论
为什么被折叠?



