闭包:
闭包简单来讲是指使用了外部环境变量的函数,函数在声明定义之时在代码块内部的变量属于locals(),但是如果引用使用了函数代码块外部的变量,那么就可以实现一些功能,比如我们需要实时了解得知一个函数内部某些变量的值,但是在执行完毕或者执行之前函数内部属于局部,其中的变量是局部变量,可能存在无法访问的情况,或是被垃圾回收机制处理掉。那么我们可以在函数内部定义一个可以访问本函数变量的函数成员,然后返回这个函数成员,这样作为返回值的子函数所访问到的外部函数的变量就不会被清零引用值,不会被清空内存。
举例子就是:
1 #__closure__#新建闭包函数等于新建函数+附加自由变量 2 #函数编译过程中内部函数会有一个闭包的特殊属性__closure__(func_closure)。__closure__属性是一个由cell对象组成的元组,包含了由多个作用域引用的变量 3 def outter(): 4 name='jack'#定义了,被下层函数使用 5 age=24#定义了,被下层函数使用 6 address='BJ'#定义了,被下层函数做返回值 7 hobbie='fishing'#定义了但未被本函数和下层函数使用 8 9 def inner1(): 10 new_name=name[0:3] 11 new_age+=age 12 inner1_l=locals() 13 inner1_g=globals() 14 return address,inner1_l#使用outer的 15 return inner1 16 inner1 = outter()
17
这里通过返回值我们就可以用inner1()返回值来访问outter()一些局部变量,所谓闭包,可以看做多做一层包装。(还记得c++一个返回引用类型的函数的返回值是可以修改的吗?)
装饰器:
在已有的函数的基础上包装一个能够接受函数的高阶函数,从而添加已有函数的功能同时不改变名字。
使用python的@语法糖来对函数进行修饰。
1 # 使用 @ 语法糖 2 # @是python装饰器的简便写法,是Python的语法糖 3 4 import datetime 5 6 def outer_fun(fun): 7 #do something you want here 8 str1='This is string from outer' 9 10 def inner(): 11 print(2) 12 print(str1) 13 print('from inner to execute:',fun.__name__) 14 print('the',fun.__name__,'result:',fun()) 15 print('extra:',datetime.datetime.now()) 16 17 return inner 18 19 #装饰器语法糖在要被包裹的函数前声明。 20 #@后面的函数名,是把下边函数进行包裹的函数的名字outer_fun 21 @outer_fun#为fun1函数添加一个装饰器函数叫outer_fun 22 def fun1(): 23 return 'this is fun1 function--' 24 25 @outer_fun#为fun1函数添加一个装饰器函数,叫outer_fun #fun2 = outer_fun(fun2) 26 def fun2(): 27 return 'this is fun2 function--' 28 29 # 装饰器在Python使用如此方便都要归因于 30 # Python的函数能像普通的对象一样能作为参数传递给其他函数 31 # 可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内 32 33 #装饰器是AOP思想的体现。Aspect Oriented Programming(面向切面编程) 34 fun1() 35 dd=9 36 print(dd) 37 fun2()
38 def outter(func):
39 print('This is the outside.')
40 func()
41 return func
42 @outter
43 def fun():
44 print("I am the inside one!")
45 return None
这里要注意给函数添加功能的装饰器是是会返回一个函数的,也就是我们在原有函数的基础上多加了一些功能作为新函数,这个新函数又怎样被返回呢?
就必须在外部再包一层函数来返回这个新函数,才能保证功能的实现。
以上的语法糖@outter加上之后的def fun()可以直接认为是fun = outter(func),这里还要注意,函数是一个一等公民,在python中也可以是对象,使用变量指向一个函数,同时也要注意()是调用运算符,函数只有名字的时候是代表函数对象本身的,加上()可能涉及调用以及返回值。
方便开发者修改已有的函数功能,且不必要重新改名字。
关于装饰器详情可以看https://www.runoob.com/w3cnote/python-func-decorators.html