今天又把《流畅的Python》翻了一遍,更进一步的理解了Python的global、nonlocal关键字以及闭包和装饰器。
global关键字:
针对定义在python的全局变量,与之相对的是局部变量(一般定义在函数中),全局变量和局部变量的一个主要区别是 :
在函数内部,全局变量只能被访问,而不能直接被操作,如果想让全局变量能紧随函数操作而变化,则需要在函数内部使用global关键字,见下面例子
?例1:不直接操作全局变量,全局变量值不发生变化
outer = '全局变量'
def f1():
a = outer + 'ok'
print(a)
f1()
print(outer)
?输出 : ?
全局变量ok
全局变量
例2 :直接在函数内部操作全局变量,导致报错
outer = '全局变量'
def f2():
outer = outer + 'ok'
print(outer)
f2()
print(outer)
输出 :
UnboundLocalError: local variable 'outer' referenced before assignment
例子3 :函数内部可以直接操作全局变量,并且使得全局变量在函数调用紧跟变化(这里我调用两次,让结果呈现明显)
def f3():
global outer
outer = outer + 'ok'
print(outer)
f3()
print(outer)
f3()
print(outer)
输出 :
全局变量ok
全局变量ok
全局变量okok
全局变量okok
nonlocal关键字:
如果我在定义函数时,在函数内部又定义了一个函数,像下面这样,
?
def outer():
outerNum = 10
def inner():
pass
?
如果我想在内部函数里面调用外部函数的outerNum,并且让外部outerNum跟随内部函数调用变化而变化,那就需要nonlocal关键字,下面再看几个和上面global类似的例子便于理解
?例1 :这里我没有使用nonlocal,所以outerNum不随内部调用而变化
def outer():
outerNum = 10
def inner():
innerNum = outerNum + 10
print(innerNum)
inner()
print(outerNum)
outer()
输出 :?
20
10
例2:这里由于没有使用nonlocal关键字就在内部函数对outerNum进行操作,导致报错
def outer():
outerNum = 10
def inner():
outerNum = outerNum + 10
print(outerNum)
inner()
print(outerNum)
outer()
输出 :?
UnboundLocalError: local variable 'outerNum' referenced before assignment
例3 : 在内部函数使用nonlocal调用外函数变量,外部函数变量内部函数调用而变化(这里多调用几次为了更加明显)
def outer():
outerNum = 10
def inner():
nonlocal outerNum
outerNum = outerNum + 10
print(outerNum)
inner()
print(outerNum)
inner()
print(outerNum)
inner()
print(outerNum)
outer()
输出 :
20
20
30
30
40
40
闭包 :
闭包,说白了,样貌就是嵌套函数,只不过外部函数只能调用内部函数,而内部函数可以调用外部函数的变量(这时候,上述的nonlocal关键字就起到了作用),我曾经看过一个Dart语言讲师提到的 —— 闭包的优点:
1. 常驻内存????????????????2. 不污染全局
看下面这个例子——一个根据持续添加数值求总体均值的函数 :
def averageNUM():
nums = []
def inner(anum):
nums.append(anum)
return sum(nums) / len(nums)
return inner
arg = averageNUM()
print(arg(1))
print(arg(2))
print(arg(3))
结果 :
1.0
1.5
2.0
由例子可以看出——由于值变成了常驻内存,从而在函数结束后不会释放(但是这样占用内存啊)。
这样定义闭包的形式看起来很像匿名函数,但是匿名函数每次使用之后都会释放内存(用完就扔)。
装饰器 :
在介绍装饰器之前先看两个功能相同的函数 —— 都是求数字4的平方根的函数?:?
def useFunc(func):
return func(4)
def getSqrt(n):
return n ** .5
print(useFunc(getSqrt))
# 2.0
def useFunc(func):
return func(4)
@useFunc
def getSqrt(n):
return n ** .5
print(getSqrt)
# 2.0
??方案二即一个简单的装饰器 —— 根据方案一就可以大致理解,函数的参数是函数时,可以选择装饰器,如果只是一个函数当参数,一个主函数是看不出什么的;如果对多个函数掉同一个装饰器,就能体现装饰器的神奇功能——拓展额外功能、统一便于管理。
def useFunc(func):
print('额外功能')
return func(4)
@useFunc
def getSqrt(n):
return n ** .5
@useFunc
def anotherFunc1(n):
return n ** 2
@useFunc
def anotherFunc2(n):
return n * 2
print(getSqrt)
print(anotherFunc1)
print(anotherFunc2)
输出 :?
额外功能
额外功能
额外功能
2.0
16
8
OK, 差不多就是我今天的收获了,bye……
|