python中的闭包和装饰器

从新学习完了函数,是时候将其中的一些重点从新捋一捋了,本次总结的东西只有闭包和装饰器python

1.闭包闭包

闭包是python函数中的一个比较重要功能,通常闭包都是用在装饰器上,通常学完闭包就会去学习装饰器,这俩个老是让初学时的我一脸懵逼,如今好好捋一捋。函数

1.1 闭包的定义学习

  • 内层函数对外层函数(非全局)调用
  • 闭包通常存在于内部函数
  • 闭包都是通常一层一层退出,最后退出函数外返回值
  • (自我理解)函数外部对于函数内部的调用以及对内部函数的值调用

1.2 闭包的判断测试

__closure__的使用spa

####不是闭包
name = 'test'
def func():
    def inner():
        print(name)
    return inner()
f = func()
print(f.__closure__[0].cell_contents)
#结果
TypeError: 'NoneType' object is not subscriptable
#结果就是没有闭包调用的值,就不是闭包


#是闭包
def func():
    name = 'test'
    age = 18
    def inner():
        print(name)
        print(age)
    return inner
f = func()
print(f.__closure__[0].cell_contents)
print(f.__closure__[1].cell_contents)
#结果
18
test

1.3 闭包的机制设计

在编译器中碰到函数,在函数执行结束后会将名称空间关闭,不过对于闭包,内部机制是碰到闭包的空间就不会关闭,在一段时候不在调用或者使用后才会关闭日志

1.4 闭包的使用以及使用场景code

用闭包的形式写一个数字的连加blog

def func(i):
    num = 1

    def inner():
        nonlocal num
        num += i
        print(num)

    return inner
f = func(3)
for i in range(5):
    f()

上面这个只是一个很简单的功能,对于闭包在一些平常的使用场景有

装饰器和爬虫的一部分使用

2.装饰器(一个需求引起的血案)

需求:公司内一个项目运营了一段时间,TeamLeader以为如今的代码执行效率有点低下,须要对现有函数的的执行效率进行一次测试。

2.1 直接调用

在最开始的时候没想完整,只是实现功能,代码以下

import time
def func1():
    print('func1')
    time.sleep(0.5)

def func2():
    print('func2')
    time.sleep(0.6)

def test(f):
    stat_time = time.time()
    f()
    end_time = time.time()
    print('执行效率为%s'%(end_time-stat_time))

test(func1)
test(func2)
#结果
func1
执行效率为0.5010201930999756
func2
执行效率为0.6002087593078613

对于这个,你的领导绝对想要杀了你,这样的话打乱了整个项目的函数调用顺序,测试一遍,所有的函数基本无法用了,须要改进,改进目的是减小对于已有函数的影响

2.2 必定的假装

import time
def func1():
    print('func1')
    time.sleep(0.5)

def func2():
    print('func2')
    time.sleep(0.6)

def test(f):
    stat_time = time.time()
    f()
    end_time = time.time()
    print('执行效率为%s'%(end_time-stat_time))

f = func1
func1 =test
func1(f)
f1 = func2
func2=test
func2(f1)
#结果和上面一致

和最开始的那个版本相比呢,有必定的假装了,但是执行的方式和之前就不同了,还有一个比较重要的是这样执行函数不能传参数,项目的函数之间调用必定是有参数的,因此这个版本也PASS了,继续想吧,下个阶段实现的目的是执行函数和之前一致

2.3 比较好的假装

def test(f):
    def inner():
        stat_time = time.time()
        f()
        end_time = time.time()
        print('执行效率为%s'%(end_time-stat_time))
    return inner
#结果
func1
执行效率为0.5008118152618408

不太好理解,借用老师上课的一张图,有空了在去作动图吧

TIM图片20190104221931

这个版本已经和很是接近完整版了,不过python中有语法糖的功能,能够将上述函数尽可能减小

2.4 假装成功-装饰器

看一下代码

import time

def test(f):
    def inner():
        stat_time = time.time()
        f()
        end_time = time.time()
        print('执行效率为%s'%(end_time-stat_time))
    return inner
@test
def func1():
    print('func1')
    time.sleep(0.5)
@test
def func2():
    print('func2')
    time.sleep(0.6)

func1()
func2()

看一下这个@test就是这个小老鼠,装饰器加上下面的函数名,就自动生成一个装饰器,这样就看着很顺眼了,不过还有一些功能啊,有些函数仍是有一些参数须要传参,貌似如今的功能尚未实现哎,在改改吧。

2.5 装饰器的传参

既然传参,那么参数的数量就不一致,这样就须要动态传参了,看代码

import time

def test(f):
    def inner(*args,**kwargs):
        stat_time = time.time()
        f(*args,**kwargs)
        end_time = time.time()
        print('执行效率为%s'%(end_time-stat_time))
    return inner
@test
def func1(x):
    print(x)
    time.sleep(0.5)
@test
def func2(x,y):
    print(x,y)
    time.sleep(0.6)

func1('a')
func2('b',[1,2,3,4])
#结果
a
执行效率为0.5004942417144775
b [1, 2, 3, 4]
执行效率为0.6011292934417725

2.6 装饰器的返回值

上面那个应该是已经很是很是接近于彻底体了,即便是函数,有了传参,那么就有返回值,那么返回值怎么才能看到呢,代码以下

import time

def test(f):
    def inner(*args,**kwargs):
        stat_time = time.time()
        r1 =f(*args,**kwargs)
        end_time = time.time()
        print('执行效率为%s'%(end_time-stat_time))
        return r1
    return inner

@test
def func1(x):
    print(x)
    time.sleep(0.5)
    return 666
@test
def func2(x,y):
    print(x,y)
    time.sleep(0.6)
    return 333

print(func1('a'))
print(func2('b',[1,2,3,4]))
#结果
a
执行效率为0.5004842281341553
666
b [1, 2, 3, 4]
执行效率为0.6007628440856934
333

写到如今才终于把整个迭代器搞明白了,哎,之后的工做就是伴随着装饰器啊Thinking smileThinking smileThinking smile

2.7 装饰器的总结

对上述全部的迭代器总结下就是下面这个例子了

def test(f):
    def inner(*args,**kwargs):
        #对函数进行装饰以前的代码
        ret = f(*args,**kwargs)#返回值
        #对函数进行装饰以后的代码
        return ret#将函数的返回值返回出去
    return inner
#装饰器的基本结构就是这个啦。。。
装饰器:装饰器的本质是闭包,并且装饰器其实就是个函数而已。
装饰器:在不改变原函数调用方式上,给原函数增长了一些额外的功能。登陆验证,写日志,执行效率等等。

3.延伸:代码开发的开放封闭原则

开放封闭原则:
对拓展开放的:
咱们说,任何一个程序,不可能在设计之初就已经想好了全部的功能而且将来不作任何更新和修改。
因此咱们必须容许代码扩展、添加新功能。
对修改是封闭的:
就像咱们刚刚提到的,由于咱们写的一个函数,颇有可能已经交付给其余人使用了,
若是这个时候咱们对其进行了修改,颇有可能影响其余已经在使用该函数的用户。
装饰器就是开放封闭原则完美的体现。