函数的嵌套定义
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:05'
def f1():
print('in f1')
def f2():
print('in f2')
f2()
f1()
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:09'
def f1():
def f2():
def f3():
print('in f3()')
print('in f2()')
f3()
print('in f1()')
f2()
f1()
nonlocal关键字的作用
在有嵌套的函数中,如果我们内部的函数使用外部的变量的时候,如果只是访问,可以正常的访问.
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:15'
def outsite():
var = 5
def inside():
print(var)
inside()
outsite()
但是如果要修改的话,必须使用nonlocal关键字进行声明,声明这个变量是外部变量.
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:15'
def outsite():
var = 5
def inside():
# print(var) 这里会报错,nonlocal声明的变量在内部函数之前不能出现.
nonlocal var
var = 11
print(var)
inside()
outsite()
闭包的概念
首先看一个经典的闭包
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:36'
def outer(arg):
var = 1
def inside():
print(arg,var) #内部函数引用了外部变量
return inside #外部函数返回的是内部函数
闭包的形成,必须满足三个条件
1. 必须是嵌套函数
2. 内部函数必须引用了外部变量(不是全局变量)
3. 外部函数的返回值必须是内部函数
一句话解释就是,当一个函数被当成对象返回的时候,夹带了外部变量,就形成了一个闭包.
如何理解闭包呢?
闭包的最大意义就是它带了外部函数中的变量,同一个函数可以带不同的外部变量.并且即使这个外部变量所在的外部函数不存在了,这个变量也会一直存在.它存在的方式就是在内部函数对象的closure属性,里面存放了一个元组,保存了所有的外部变量,以及它对应的值.所以内部函数携带的这个外部变量才可以持久的存储和使用.其实外部变量已经不在内存中,只是被内部函数以另外一种方式记录了下来.
如何判断一个函数是不是闭包函数
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 20:02'
# 输出的__closuer__有cell元素:是闭包
def func():
name = 'eva'
def inner():
print(name)
print(inner.__closure__)
return inner
f = func()
f()
name = 'egon'
def func():
def inner():
print(name)
print(inner.__closure__)
return inner
f = func()
f()
装饰器
装饰器函数是什么?
首先要明白两点:装饰器利用了闭包特性,还利用了函数可以作为参数和返回值使用
装饰器函数是一个嵌套函数,外层函数的返回值必须是被装饰过的函数.
简单的来说,装饰器就是一个包装函数,它本质上是一个闭包函数.一般就是传入一个函数,在不修改原来函数以及其调用方式的前提下为原来的函数增加新的功能.通常的做法是在内层的函数中调用被装饰的函数,然后再调用之前或者之后可以增加额外的代码,来增加一些额外的功能.达到扩展功能的目的.其实装饰器函数本质上是函数名和函数地址的重新绑定.被装饰的函数虽然看起来和原来的函数名字一样,但是在其内存中已经修改了绑定关系,它已经绑定到我们的装饰器函数的内层的那个闭包函数上了.
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 20:28'
import time
# 装饰器函数
def deco(func):
def wrapper():
startTime = time.time()
func()
endTime = time.time()
print('程序执行了{}秒'.format(endTime - startTime))
return wrapper
@deco
def myfunc():
print('hello')
time.sleep(1)
print('world!')
# @deco的作用就相当于是改变被装饰的函数变量的值,首先将其作为参数传递为装饰器函数,用它的返回值,赋值给被装饰的函数
# myfunc = deco(myfunc) # 相当于是myfunc = wrapper myfunc增加一个统计时间的功能
# 被装饰的函数经过装饰后,其实就变成了装饰器函数的内部函数,也就是闭包函数.
if __name__ == '__main__':
myfunc()
装饰器的一般定义方式:
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 20:46'
# 可以传递参数的装饰器函数
def timer(func):
def inner(*args, **kwargs):
'''被装饰函数执行之前要做的事情'''
re = func(*args, **kwargs)
# 被装饰函数执行之后要做的事情
return re
return inner
# 但是这样有一个问题,就是我们被装饰的函数的一些属性会改变.
@timer
def func1(a,b):
print(a + b)
@timer
def func2(a):
print(a)
print(func1.__name__,func2.__name__)
如果不想修改原来的被装饰的函数的name,doc文档结构的话,可以使用@wraps 在functiontoos包中
所以比较规范的装饰器定义如下:
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 20:57'
from functools import wraps
def user_login_data(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@user_login_data
def f1():
print('aaa')
@user_login_data
def f2():
print('bbb')
if __name__ == '__main__':
print(f1.__name__)
print(f2.__name__)
Python多个装饰器的执行顺序问题
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/7 17:18'
def deco1(func):
print('outer1')
def inner1(*args,**kwargs):
print('inner1')
func(*args,**kwargs)
return inner1
def deco2(func):
print('outer2')
def inner2(*args,**kwargs):
print('inner2')
func(*args,**kwargs)
return inner2
@deco2
@deco1 # test = deco1(test) inner1 test = deco2(inner1) = inner2()
def test():
print('test')
if __name__ == '__main__':
test()