python闭包和装饰器¶
闭包的概念¶
闭包是指在方法内引用方法外定义的非全局变量,如下示例是在内部方法inner使用外部方法outer中的变量num。
调用test()方法返回的num值是10,也就是说在inner中使用的是外部方法outer()中定义的变量num,但是,在调用test()方法时,outer函数已经返回了,本地的作用域也不存在了,是怎么得到num的值的呢?此时便涉及到变量的作用域相关内容.变量的作用域¶
大家都知道,变量一般分为局部变量和全局变量,如下例子:
num1 = 10
def outer():
num2 = 20
def inner():
global num1
num3 = 30
return num1 + num2 + num3
return inner
test = outer()
test()
If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal.
If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.)
If a variable is used in a code block but not defined there, it is a free variable. 翻译:
如果在代码块中绑定一个名称,除非声明为nonlocal,否则它是该代码块的局部变量。
如果一个名称在模块级别绑定,它是一个全局变量。(模块代码块的变量是局部和全局的。)
如果一个变量在代码块中使用但未在那里定义,它是一个自由变量。
根据第三点可以看出,如果一个变量在一个代码块中使用,但是没有在代码块中定义,就是自由变量(未在本地作用域中绑定的变量)。
global和nonlocal¶
在python中,global和nonlocal关键字用于在局部作用域中引用外部变量,但他们的作用范围有所不同。
global关键字¶
作用在函数内部修改全局变量的值,或声明一个变量为全局变量。
注意: * 若不使用global,函数内部对同名变量的赋值会创建局部变量。 * global声明需要在变量使用前。nonlocal关键字¶
用在内层函数中修改外层(非全局)嵌套函数的变量。 实例1:
注意: * 只能用于嵌套函数中。若外层函数无该变量,会引发SyntaxError示例2:
如果直接对num进行自增操作,会发现有报错,local variable 'num' referenced before assignment,也就是说你在inner内使用num += 1时,相当于num = num + 1,此时对num进行赋值python默认num是局部变量,但是inner内并没有定义num,所以会报错。 我们不妨想想还有什么其他方法可以解决示例2的问题,如果把num改成list类型,可不可以呢?示例3:
通过运行,我们发现可以得到想要的结果,因为list是可变类型,此时num指向的是自由变量num,并对num中的数据进行了改变。但是这样每次都把不可变数据转换成可变数据进行传递太麻烦了,所以python3引入了nonlocal声明,作用是把变量标记为自由变量,即使在函数中为变量赋予了新值,也会变成自由变量。
示例4:
def outer():
num = 10
def inner():
nonlocal num
num += 1
return num
return inner
test = outer()
test()
装饰器¶
装饰器的概念: 对方法(函数)进行装饰,在方法运行前后添加其他功能,返回新的方法。
示例:
import time
def outer(func):
def inner():
time1 = time.time()
func()
time2 = time.time()
return time2 - time1
return inner
@outer
def test():
print("test")
装饰器的执行顺序: 装饰器在被装饰的函数定义之后立即运行,通常是在导入时(即python加载模块时)
示例:
def outer(func):
print("%s outer running" % func)
def inner():
print("%s inner running" % func)
return func
return inner
@outer
def test1():
print("test1 runing")
@outer
def test2():
print("test2 runing")
def test3():
print("test3 runing")
def main():
print("main runing")
test1()
test2()
test3()
if __name__ == "__main__":
main()
<function test1 at 0x104b4bd90> outer running
<function test2 at 0x104b4bea0> outer running
main runing
<function test1 at 0x104b4bd90> inner running
<function test2 at 0x104b4bea0> inner running
test3 runing
参数化装饰器: 参数化装饰器即为带参数的装饰器,如果装饰器需要额外的参数,就可以创建一个装饰器工厂函数,把参数传给它,如下例:
示例:
register = set()
def dec(active=True):
def outer(func):
print("running %s (active=%s)" % (func, active))
if active:
register.add(func)
else:
register.discard(func)
return func
return outer
@dec(active=False)
def test1():
return "runing test1"
@dec()
def test2():
print("runing test2")
def test3():
print("running test3")
def main():
print("main runing")
test1()
test2()
test3()
print(register)
if __name__ == "__main__":
main()