1、
内部函数
:内部函数和外部函数共用外部函数的参数,并返回内部函数的调用。
作用:避免循环和代码的堆叠重复。
例如:
def test(*args): #外部函数test
def add(*args): #内部函数add,显示的调用外部函数的参数
return args
return add(*args) #返回内部函数add的调用
2、
闭包函数
:内部函数和外部函数使用不同的参数,且内部函数会调用外部函数的参数作为自由变量,并返回内部函数的调用。这一类的内部函数叫做闭包函数。
函数闭包要满足什么条件(缺一不可):
1)必须嵌套函数
2)内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量
3)外部函数必须返回内嵌函数——必须返回那个内部函数
例如:
def bar(multiple): #外部函数
def foo(n): #闭包函数
return multiple ** n #与内部函数不同的是,闭包函数的参数和外部函数的参数不同,且闭包函数内会调用外不函数中定义的变量
return foo # 返回闭包函数的调用
本列中,bar外部函数参数为multiple,foo闭包函数的参数为n,且foo函数内部调用multiple作为自由变量。
执行bar(2)(3):参数2、3分别传入bar、foo函数,return foo ------- return 2** 3 结果为8
闭包中引用的自由变量有如下的认识:
(1)闭包中的引用的自由变量只和具体的闭包有关联,闭包的每个实例引用的自由变量互不干扰。
(2)一个闭包实例对其自由变量的修改会被传递到下一次该闭包实例的调用。
3、
装饰器
:装饰器实质上是一个函数,它把一个函数作为输入并且返回另一个函数
装饰器要满足如下条件:1、不能改变原来函数的代码。2、为函数添加新的功能。3、不能改变函数的调用方式。 使用函数闭包完全可以做到这一点。
作用:经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验,有了装饰器可以抽离大量与函数功能本身无关的雷同代码并继续重用,提高程序的可重复利用性,并增加程序的可读性。
#使用闭包函数的装饰器,foo被装饰器dec修饰
def dec(f):
n = 3
def wrapper(*args,**kw):
return f(*args,**kw) * n
return wrapper
@dec #装饰器,将装饰器下函数作为参数输入装饰器dec函数中,并返回另一个函数
def foo(n): #被装饰的函数foo
return n * 2
#对foo进行装饰以后,foo的函数命名空间发生了变化,foo本来是属于全局命名空间,被修饰后,命令空间变为局部命名空间
本例中dec为装饰器,foo为原函数即被装饰器装饰的函数,wrapper为闭包函数。
程序执行过程:foo作为参数代入dec函数中foo3,foo函数返回值为n2,故最后结果为n23
带参数的装饰器
def dec(level):
def dect(f):
n = 3
def wrapper(*args,**kw):
return f(*args,**kw) * n
return wrapper
return dect
@dec(5) #装饰器,5这个参数作为dec的输入,将装饰器下函数foo作为参数输入dect函数中
def foo(n):
return n * 2
类装饰器
class Foo(object):
def __init__(self,func):
self.func = func
def __call__(self):
self.__func()
@Foo #Foo为类装饰器
def bar():
print('bar')
在Python程序执行过程中,会有局部命名空间、全局命名空间和内建命名空间同时存在。局部命名空间记录函数内部的变量、传入函数的参数、嵌套函数等被命名的对象;全局命名空间记录模块的变量、函数、类及其它导入的模块等被命名的对象;内建命名空间记录Python自身提供的函数、模块等被命名的对象。
functools.wraps
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,变成了装饰器中闭包函数的信息了。主要是原函数的命名空间发生变化。为了避免这种问题,可以使用functools.wraps装饰器保留住原函数的属性。
from functools import wraps
def tracer(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print('%s(%r,%r)->%r'%(func.__name__,args,kwargs,result))
return result
return wrapper
@tracer
def fibonacci(n):
if n in (0,1):
return n
return (fibonacci(n-1)+fibonacci(n-2))
fibonacci(3)
print(fibonacci)
print('help:')
help(fibonacci)