所谓闭包,就是将组成函数的语句和这些语句的执行环境打包在一起时,得到的对象。
下面是闭包的栗子:
#foo.py foo文件
filename = 'foo.py'
def call_func(f): #这个函数就是说,要返回调用那个作为参数的函数
return f()
#func.py 另一个叫func的文件
import foo #在这里导入上一个 foo 文件
filename = 'func.py'
def show_filename():
return "filename: %s" %filename
print( foo.call_func(show_filename)) # 返回:filename: func.py
#注意:实际发生调用的位置,是在foo.call_func函数里
这个栗子就是想说明,有两个文件foo 和 func,其中都有一个同名filename的定义。在func文件中导入了foo文件后,运行foo.call_func(show_filename),尽管实际调用show_filename的位置在foo.py的call_func内部,但是所返回的filename是在func文件中定义的那个。
在下面这个嵌套函数中看
#enclosed.py
import foo # 导入了poo 文件,call_func功能: 返回调用作为参数的函数
def wrapper(): #这个wrapper函数没有返回值,打印调用那个call_func函数
filename = "enclosed.py" #嵌套函数内部也有一个同名filename变量
def show_filename():
return "filename: %s" % filename #执行到这句的时候,就要开始找,究竟用哪个 filename
print foo.call_func(show_filename) #输出:filename: enclosed.py
举这个栗子想说明:闭包将会捕捉内层函数执行所需的整个环境
-
LEGB法则就是查找顺序。
当代码执行到filename: %s" % filename时,解释器按照循序查找filename变量:
先在show_filename函数中找,然后是到wrapper函数中找(多层嵌套的话,就由内而外查找),然后到enclosed.py中找,最后到内置模块。按顺序一旦找到就不在到外层去找了,如果一直找不到,那就会出现NameError异常。 -
装饰器&语法糖就是@log
提到闭包的重要特性:封存上下文,这一特性可以巧妙的被用于现有函数的包装,从而为现有函数更加功能。而这就是装饰器。
(原本想找资料加深对装饰器的理解,但是,现在这个就拿来读读吧)
import logging #这个模块没具体查,是跟记录日志有关的
logging.basicConfig(level = logging.INFO)
#通过logging.basicConfig函数对日志的输出格式及方式做相关配置
def add(a,b): #这个add函数是要被“装饰的”
return a+b
def checkParams(fn): #通过封存的fn,继续调用原始的add进行+运算。
def wrapper(a,b):
if isinstance(a,(int,float)) and isinstance(b,(int,float)):##检查参数a和b是否都为整型或浮点型 isinstance函数的使用
return fn(a,b) #是则调用fn(a, b)返回计算结果
#否则通过logging记录错误信息,并友好退出
logging.warning("variable 'a' and 'b' cannot be added")
return
return wrapper #fn引用add,被封存在闭包的执行环境中返回
#将add函数对象传入,fn指向add
#等号左侧的add,指向checkParams的返回值wrapper
add = checkParams(add) #这里一般会被写成语法糖简化
add(3,'hello')
诶。。。乱七八糟。。的
看这个吧https://www.zhihu.com/question/25950466
网友评论