本文共 4042 字,大约阅读时间需要 13 分钟。
Python与大多数编程语言一样,搜索变量值的时候,即命名空间的规则,会采用’就近原则’:
由近及远依次为: 本地作用域(Local) --> 外部嵌套函数作用域(Enclosing Local) --> 全局/模块作用域(Global) --> 内置作用域(Built-in).a = str(1) # str:Built-inb = 3 # b:Globaldef f1(): print(b) # b:Global a = 3 # a:Local print(a)def f2(): a = 3 # a:Enclosing def f3(): b = 3 # b:Local print(b)
示例1:
a = 4def foo(): a = 3foo()print(a) # 4
示例2:
a = 4def foo(): a = a + 3foo()# local variable 'a' referenced before assignment
如何在内部作用域中去修改外部作用域的变量值呢?这里推出两个关键字来声明外部作用域变量:global、nonlocal 。内部作用域中要修改外部作用域变量的值时。要用 global、nonlocal 关键字声明外部作用域变量。
a = 3def foo(): global a # 使用 global 声明 a ,便可以在函数中修改 a 的值 a = 4foo()print(a) # 4 def f1(): a = 3 def f2(): nonlocal a # 使用 nonlocal 声明 a, 便可以在嵌套的函数内部修改 a 的值 a = a + 1 print(a) f2()
def check(val): #以16进制打印val的id值 print('%x'%id(val)) if val > 60: print('pass') else: print('fail') def func(): print(val) func() return funcif __name__ == "__main__": f = check(90) f() print(f.__closure__) # closure:内部函数中对enclosing作用域的变量进行引用 ---------output-------------------557a7165b5e0 # 此时可看出val的id值为1009dd4a0pass90---------90---------(,) |
按照python的变量回收机制,val在check函数执行完成后,应该被回收掉,为什么会出现调用f()时,出现val的值呢?f中存在int类型的val值的引用,因为python采用引用计数的垃圾回收机制,当check()函数执行完成后,val对象被保存在func的函数属性中,仍存在引用,所以并没有对val进行垃圾回收。
什么是闭包:
闭包指延伸了作用域的函数,其中包含函数定义体中引用、但是不在定义体中定义的非全局变量。函数是不是匿名的没有关系,关键是它能访问定义体之外定义的非全局变量
总结:闭包实质上是一个函数,它能够访问函数体之外定义的非全局变量,而这个非全局变量指的就是自由变量。它使得函数在执行后,函数的返回对象不会被内存回收,并且闭包中包含着自由变量,只要闭包能被访问到,自由变量就可以被访问。
示例1:
下面举一个例子, 定义一个 avg 函数,参数为一个值, 不断累加的计算从开始到现在所接收的全部值的平均值
def make_average(): series = [] def average(value): series.append(value) total = sum(series) return total / len(series) return averageavg = make_average() # 1print(avg(10)) # 2print(avg(20)) # 3#-----output----------10.015.0
上面的例子效率比较低, 没一次都得 sum.我们难道不可以保存每一步计算的 total 吗?
示例2:
def make_average(): count = 0 total = 0 def average(value): count += 1 total += value return total / count return averageavg = make_average()avg(10)# UnboundLocalError: local variable 'count' referenced before assignment
示例3:
我们需要使用 nonlocal 将 count 和 total 变成自由变量def make_average(): count = 0 total = 0 def average(value): nonlocal count, total count += 1 total += value return total / count return average# 开始调用.返回一个函数对象,并且这个对象是一个闭包avg = make_average()print(avg(10))print(avg(20))#-----output-----------------------10.015.0
装饰器用来’装饰’一个函数,为函数添加额外的功能。
装饰器接收一个函数作为参数,装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。 举例, 我们定义一个装饰器,用来计算并且显示每个函数运行的时间。import timedef decorate(func): def wrapper(*args): to = time.perf_counter() result = func(*args) t1 = time.perf_counter() - to print(f'运行时间为:{t1}') return result return wrapper
@decoratedef foo(n): i = 0 while i < n*n: i += 1 return iprint(foo(600))# 程序的运行时间为:0.022877089999383315# 360000
@decorate
是一个语法糖, 等同于 func = decorate(func), 所以此时 func 是 wrapper 函数的引用.
转载地址:http://bsili.baihongyu.com/