''''''
"""
闭包函数
1.闭:定义在函数内部的函数
2.包:内部函数引用了外部函数作用域的名字
"""
# def outter(): # 定义一个外层函数
# x = 111 # 在外层函数的局部名称空间定义变量x = 111
# def inner(): # 定义一个内层函数
# print(x) # 打印x
# return inner # 外层函数返回值为 内层函数名
# res = outter() # res就是inner函数内存地址,调用外层函数 三步:定义x,定义内层函数,返回内层函数名
#
# def func(): # 定义函数 检查语法不执行
# x = 333 # 在函数的局部名称空间定义变量x = 333
# res() # 调用res 即调用inner() 内层函数 检查语法不执行
# func() # 执行func()
# # 执行顺序: 执行func:
# # 第一步 在函数的局部名称空间定义变量x = 333,
# # 第二部 执行inner(),打印x,在inner的局部名称空间找不到,去上层outter的局部名称空间找,找到了,打印111


# 给函数体传值的第一种方式 传参
# def index1(username):
# print(username)
#
# # 给函数体传参的第二种方式 闭包 # 执行顺序
# def outter(x,y): # 定义一个外层函数并设置位置形参 x y 定义函数,检查语法不执行 # 2
# # x = 1 # 调用函数时候,传入位置形参,默认在 外层函数的局部命名空间 做了赋值操作 # 3
# # y = 40 # 调用函数时候,传入位置形参,默认在 外层函数的局部命名空间 做了赋值操作 # 4
# def my_max(): # 定义内层函数 # 5
# if x > y: # 判断条件 # 9
# return x # 执行判断条件下的代码 # 10
# return y # 判断条件非会执行什么 # 10
# return my_max # 返回内层函数名 # 6
# res1 = outter(1,40) # res就是my_max函数的内存地址 # 7 1
# # 这一步看似是个赋值操作,其实后面是个调用outter()函数的操作,然后把函数执行的返回结果赋值给res1 #
# # 这一步因为有调用函数,执行优先级别最高,所以是先执行函数然后再赋值给res1,不是先赋值 #
# # 调用函数,执行函数时,需要传递两个位置形参 #
# print(res1()) # 打印res1的执行结果,即打印 my_max的执行结果 先执行函数 后打印 # 11 8
# print(res1()) # 打印res1的执行结果,即打印 my_max的执行结果 先执行函数 后打印 #

# res2 = outter(90,200)
# print(res2())
# print(res2())




"""
装饰器:
器:就是一个工具
装饰:给被装饰对象添加新的功能

为什么要用装饰器
开放封闭原则:
开放:对扩展开放
封闭:对修改封闭

装饰器(可调用对象)必须遵循的两个原则:
1.不改变被装饰对象源代码
2.不改变被装饰对象(可调用对象)调用方式
def index():
pass
index()

如何用
"""
# import time # 导入时间模块
# print(time.time()) # 打印时间戳
# # 结果为1562812014.731474 时间戳 当前时间距离1970-1-1 00:00:00相差的秒数
# # 1970-1-1 00:00:00是Unix诞生元年


# import time
# time.sleep(3) # 让cpu暂停三秒 让你的程序暂停三秒
# print('FBI warning!')
# # 执行结果,过三秒会打印字符串
#
"""
1.统计index函数执行的时间
"""
# import time
# def index():
# time.sleep(3)
# print('澳门最大线上赌场开业啦 性感tank在线发牌!')
#
# start = time.time()
# index()
# end = time.time()
# print('index run time:%s'%(end-start))
# # 打印 结束时间戳减去开始时间戳,中间的时间差 就是执行时间,主要是sleep的时间


"""
1.统计index函数执行的时间
装饰器(可调用对象)必须遵循的两个原则:
1.不改变被装饰对象源代码
2.不改变被装饰对象(可调用对象)调用方式
"""
# # 1.统计index函数执行的时间
# import time # 导入时间模块
# def index(): # 定义被装饰函数
# time.sleep(3) # cpu暂停三秒再继续执行
# print('澳门最大线上赌场开业啦 性感tank在线发牌!') # 打印字符串
# # index() 单独执行效果,延迟三秒打印字符串
# # 装饰器如下
# def outter(func): # func = 最原始的index函数的内存地址 # 定义外层函数outter,位置参数func
# # func = index # 执行外层函数时,被传参,位置实参为index,即有参数赋值这一步
# def get_time(): # 定义内层函数(新增功能获取执行时间)
# start = time.time() # 开始时间 = 打印当前时间戳
# func() # func = index函数的内存地址() 直接调用 # 执行func函数
# end = time.time() # 结束时间 = 打印结束时间戳
# print('index run time:%s'%(end-start)) # 打印执行func()前后时间差
# return get_time # 返回内层函数名(新增功能)
# index = outter(index) # outter(最原始的index函数内存地址)
# # 使用原被装饰函数名为变量 = 执行装饰器外层函数(位置实参为原始被装饰函数函数名)
# # index指向get_time函数的内存地址
# index() # 执行 (使用原被装饰函数名为新函数名的)函数 # 就执行上面这个变量名作为函数名的函数
'''
分析:
执行步骤; 全局名称空间下 一共执行五步
第一步:导入时间模块
第二步:定义被装饰函数 outter(func)(装饰器外层函数 位置形参为func)
第三步:定义装饰器函数 get_time()
第四步:将原函数名作为新函数名,并赋值,值为(调用装饰器函数 且 传入参数为(被装饰函数名))的执行结果
全局名称空间下 第四步,有两个操作 执行装饰器函数(优先级高),并赋值给新函数名(与原函数名相同)
言外之意,需要将第四步装饰器函数执行了,并且赋值,才能走到第五步,执行新的函数名(调用被装饰后的函数)
第四步 执行装饰器 步骤如下:
1 :参数赋值,装饰器被传入的位置实参为 func = index(这个index为原函数名称),这个赋值被存在 '装饰器外层函数的局部名称空间'中
2 :定义内层函数get_time,定义函数不执行,内层函数为新增功能函数
3 :返回内层函数名get_time,将内层函数名get_time作为返回结果返回
第四步 赋值 步骤如下:
1 :将(装饰器外层函数返回的内层新增功能函数的函数名)get_time 赋值给新函数名index(与原函数名称一样)
第五步:执行新函数名 index(这个为新函数名)
全局名称空间下,第四步执行完毕,执行第五步
第五步是执行装饰后的新函数,因为新函数名index 被赋值 (装饰器外层函数返回的内层新增功能函数的函数名)get_time
也就是,执行新增功能函数,即执行内层函数,执行内层函数步骤如下:
1:在装饰器内层函数的局部名称空间中定义 开始时间 = 打印当前时间戳
2:执行func函数,这一步需要找func这个变量的值,查找顺序 和 执行顺序如下:
1. 在装饰器内层函数的局部名称空间中找,没有找到
2. 在上一层装饰器外层函数的局部名称空间中找,找到了,在 四-1 这一步 func = index,这个index为原函数名称
3.执行index原函数 两步;
1. cpu暂停三秒
2. 打印 '澳门最大线上赌场开业啦 性感tank在线发牌!'字符串
3:在装饰器内层函数的局部名称空间中定义 结束时间 = 打印当前时间戳
4:打印时间差 结束时间减去开始时间
第五步执行完毕 执行效果为 延迟三秒打印字符串,打印执行时间差

定义原函数 1
定义装饰器函数 2
执行装饰器,传参原函数名,定义新功能函数 并 返回新功能函数名赋值给新函数名, 3
原函数名和新函数名一样 4
执行新函数,就是执行新功能函数,就是执行装饰器内层函数, 5
装饰器内层函数中的操作 有 执行函数为新功能函数 + 原函数 6 结束
'''



"""
函数参数的问题
无参函数和有参函数都可以直接调用???
函数可以接收任意数量的参数
"""
# # 无参数的被装饰函数
# import time # 导入时间模块
# def index(): # 定义原函数 (无参函数)
# time.sleep(3) # cpu暂停三秒之后打印
# print('澳门最大线上赌场开业啦 性感tank在线发牌!') # 打印字符串
# return 'index' # 返回index 字符串
# # res1 = index() # res1 为index函数执行结果的返回值(需要先执行函数,执行函数的优先级比较高)
#
# def outter(func): # func = 最原始的login函数的内存地址 # 定义装饰器外层函数,有位置形参func
# def get_time(*args, **kwargs): # args = ('egon',) kwargs = {} # 定义装饰器内层函数,有可变长形参
# start = time.time() # 赋值start 为 被装饰函数开始执行的时间戳
# res1 = func(*args, **kwargs) # 最原始的login函数的内存地址() 直接调用 func('egon')
# end = time.time() # 赋值end 为 被装饰函数结束执行时间戳
# print('func run time:%s'%(end-start)) # 打印时间差
# return res1 # 返回func函数执行结果返回值
# return get_time # 返回内层函数名
#
# # 无参数的被装饰函数
# index = outter(index) # 先执行调用装饰器,
# # 执行三步:1.定义内层函数,2.把index当位置实参传入装饰器,即func= index 3.将返回的内层函数函数名赋值给新函数名
# res1 = index() # 调用执行被装饰后的新函数,即执行装饰器内层函数,
# # 一共五步:1.赋值开始时间戳 2.执行index(此时func已经等于index,在上层局部名称空间找到的):停三秒 打印 返回字符串并赋值给res1
# # 3. 赋值结束时间戳 4. 打印时间差 5. 返回res1,即返回index字符串
# print(res1) # 6. 打印字符串 结束





# # 有参数的被装饰函数
# import time
# def login(name): # 定义原函数 (有参函数,位置参数name)
# time.sleep(1) # cpu暂停三秒之后打印
# print('%s is sb'%name) # 打印字符串 字符串拼接格式化输出,%s占位符 输入变量
# return 'login' # 返回login 字符串
# # res = login('egon') # res1 为login函数传参egon后执行结果的返回值(需要先执行函数,执行函数的优先级比较高)
#
# def outter(func): # func = 最原始的login函数的内存地址 # 定义装饰器外层函数,有位置形参func
# def get_time(*args, **kwargs): # args = ('egon',) kwargs = {} # 定义装饰器内层函数,有可变长形参
# start = time.time() # 打印被装饰函数开始执行时间戳
# res = func(*args, **kwargs) # 最原始的login函数的内存地址() 直接调用 func('egon')
# end = time.time() # 打印被装饰函数结束执行时间戳
# print('func run time:%s'%(end-start)) # 打印时间差
# return res # 返回func函数执行结果返回值
# return get_time # 返回内层函数名
#
# # 有参数的被装饰函数
# login = outter(login) # outter(最原始的login函数的内存地址) # 先执行调用装饰器
# # 执行三步:1.定义内层函数,2.把index当位置实参传入装饰器,即外层函数局部名称空间中func= login 3.将返回的内层函数函数名赋值给新函数名
# res = login('egon') # 调用执行被装饰后的新函数,即执行装饰器内层函数,并传实参egon
# # # 一共五步:1.可变长形参接传入的位置实参egon,即args = egon,没有关键字实参kwargs为空字典{}
# # 2.赋值开始时间戳 3.执行login(此时func已经等于login,在上层局部名称空间找到的):
# # 在本层局部名称空间找到args = egon,停三秒 打印拼接字符串 返回字符串login并赋值给res1
# # # 3. 赋值结束时间戳 4. 打印时间差 5. 返回res1,即返回login字符串
# print(res) # 6. 打印字符串login 结束


''''''
"""
语法糖在书写的时候应该与被装饰对象紧紧挨着
两者之间不要有空格
"""
# # 下面这个装饰器已经在上面叙述了执行过程,不再赘述,主要将装饰器语法糖
# import time
# def outter(func): # func = 最原始的index函数的内存地址
# def get_time(*args, **kwargs):
# start = time.time()
# res = func(*args, **kwargs) # 最原始的login函数的内存地址() 直接调用 func('egon')
# end = time.time()
# print('func run time:%s'%(end-start))
# return res
# return get_time
# # login = outter(login) # outter(最原始的login函数的内存地址)
# # index = outter(index)
# # home = outter(home)

'''
语法糖的用法以及含义
作用就是 把 原始被装修函数的函数名 当作参数 传值给装饰器函数
然后将装饰器外层函数执行结果的返回值(内层函数函数名)当作返回值返回 并赋值给 新函数名(与原函数名一致)
如下语法糖使用:就是将index函数名当作参数传递给outter函数,并将返回结果赋值给新的index 等同与 index = outter(index)
装饰器语法糖需要跟被装饰函数紧紧挨在一起,中间不能空行 !
'''
# @outter # index = outter(index) outter(最原始的index的函数的内存地址)
# def index():
# time.sleep(3)
# print('澳门最大线上赌场开业啦 性感tank在线发牌!')
# return 'index'
# # res1 = index()



'''
装饰器模板如下
'''
# def outter(func):
# def inner(*args,**kwargs):
# print('执行被装饰函数之前 你可以做的操作')
# res = func(*args,**kwargs)
# print('执行被装饰函数之后 你可以做的操作')
# return res
# return inner



"""
认证装饰器 需求:
执行函数index之前必须先输入用户名和密码 正确之后才能执行index
否则提示用户输入错误 结束程序
"""
# import time # 导入时间模块
# user_dic = {'is_login':None} # 定义一个空字典,记录登陆状态
#
# def index(name): # 定义index函数
# time.sleep(1) # 停1秒
# print('%s is dsb'%name) # 打印字符串
# return 666 # 返回666
#
# def home(): # 定义index函数
# time.sleep(1) # 停1秒
# print('home') # 打印字符串
# return 999 # 返回666
#
# def login_auth(func): # 定义装饰器外层函数,有位置形参func
# # func = index # 执行语法糖 传参调用装饰器时才会发生这个,定义新函数名(与原函数名一致)为 装饰器的返回值
# # #执行语法糖 或者 将原函数名当作参数传递时,会在外层函数的局部名称空间中定义func等于原函数,这一步容易被忽略
# def inner(*args,**kwargs): # 定义内层函数
# if user_dic['is_login']: # 判断原函数中记录登陆状态的字典中key的value是否为True
# res = func(*args, **kwargs) # 如果为True就是登陆了,则执行变量函数
# return res # 并且返回执行变量函数的执行结果
# else: # 否则输入用户名密码 登陆
# username = input('please input your username>>>:').strip()
# password = input('please input your password>>>:').strip()
# if username == '123' and password == '123': # 如果用户名密码为123,这里写死了
# user_dic['is_login'] = True # 如果用户名密码正确都是123,则修改原函数登陆状态
# res = func(*args,**kwargs) # 执行变量函数 并且返回执行变量函数的执行结果赋值res
# return res # 打印res,打印变量函数的执行结果
# else:
# print('username or password error') # 如果密码不一致,打印密码用户名错了
# return inner # 定义内层函数之后,返回内层函数函数名
# index = login_auth(index) # 执行装饰器 调用装饰器,定义新函数名(与原函数名一致)为 装饰器的返回值
# index('egon') # 执行新函数 新函数名加括号传值
# # index('egon')
# print(index) # 打印这个新函数名,发现就是装饰器内层函数的内存地址
#
# home = login_auth(home) # 执行装饰器 调用装饰器,定义新函数名(与原函数名一致)为 装饰器的返回值
# home() # 执行新函数 新函数名加括号
# # home()
# print(home) # 打印这个新函数名,发现就是装饰器内层函数的内存地址
#
# @login_auth # 用语法糖装饰执行原函数
# def index(name):
# time.sleep(1)
# print('%s is dsb'%name)
# return 666
#
# @login_auth # 用语法糖装饰执行原函数
# def home():
# time.sleep(1)
# print('home')
# return 999




'''
三层装饰器嵌套使用,解决问题;
给内层函数,新功能函数需要额外参数的解决方案
'''
# import time # 导入时间模块
# user_dic = {'is_login':None}
# def outter(func): # func = 最原始的login函数的内存地址
# def get_time(*args, **kwargs): # args = ('egon',) kwargs = {}
# start = time.time()
# res = func(*args, **kwargs) # 最原始的login函数的内存地址() 直接调用 func('egon')
# end = time.time()
# print('func run time:%s'%(end-start))
# return res
# return get_time
#
# def login_auth2(data_source,x,t):
# # data_source = 'file'
# def login_auth(func):
# # func = index
# def inner(*args,**kwargs): # 这里的参数是跟被装饰函数的参数一一对应
# if user_dic['is_login']:
# res = func(*args, **kwargs)
# return res
# else:
# if data_source == 'file':
# username = input('please input your username>>>:').strip()
# password = input('please input your password>>>:').strip()
# if username == '123' and password == '123':
# user_dic['is_login'] = True
# res = func(*args,**kwargs)
# return res
# else:
# print('username or password error')
# elif data_source == 'MySQL':
# print('from MySQL')
# elif data_source == 'ldap':
# print('ldap')
# else:
# print('暂无该数据来源')
# return inner
# return login_auth
#
# # res = login_auth2('MySQL')
# @login_auth2('file',1,2) # index = login_auth(get_time) index = inner函数的内存地址
# # @login_auth
# @outter # get_time = outter(index) index是最原始的index
# def index():
# time.sleep(1)
# print('index')
# return 'index'
# index()
#

# 装饰器在装饰的时候 顺序从下往上 上层装饰下层,下层被上层装饰
# 装饰器在执行的时候 顺序从上往下 先执行最上层,返回下层函数名,再执行,再返回更下层函数名,最后赋值给新函数名,调用执行
'''
传参调用执行三层装饰器,如下:
@三层装饰器外层函数名 或者 三层装饰器外层函数名() 这一步执行如下,一共包含三步
装饰器外层函数, 1.传参后实参赋值形参,多少个参数都可以,装饰器每部需要额外的变量参数
内层函数所需额外参数 = 外层函数传进来的实参
2.定义装饰器中层函数,3.并且返回中层函数的函数名
@三层装饰器中层函数 或者 新函数名 = 装饰器中层函数(原函数名)
装饰器中层函数, 1.传参后实参赋值形参,这一步只是将 原函数名 赋值给 变量函数名,变量函数名 = 原函数名
只有一个赋值,没有多余的参数
2.定义装饰器内层函数
3.并且返回中层函数的函数名
4.将内层函数名作为返回值,返回值赋值给新函数名 即 新函数名 = 内层函数名,后面就跟两层装饰器执行步骤一致
调用新函数,并传实参,即调用三层装饰器的内层函数,并传参:
1.将调用新函数传进来的实参,位置实参和关键字实参 赋值给 args 和 kwargs
位置实参 = args 关键字实参 = kwargs
1.执行新功能,需要参数会在内层函数局部名称空间找,没有,然后去中层函数局部名称空间找,也没有
去外层函数局部名称空间找到了,内层函数所需额外参数 = 外层函数传进来的实参
2.执行变量函数,内层函数局部名称空间没有找到变量函数,去中层函数局部名称空间找到了
变量函数名 = 原函数名,
原函数需要参数,会在内层函数局部名称空间找,找到了,位置实参 = args 关键字实参 = kwargs
即执行原函数
'''


''''''


"""
用户查看被装饰函数的函数名的时候查看到的就是被装饰函数本身
用户查看被装饰函数的注释的时候查看到的就是被装饰函数的注释
"""
# from functools import wraps
# def outter(func):
# @wraps(func) # 装饰器修复技术
# def inner(*args,**kwargs):
# """
# 我是inner函数
# :param args:
# :param kwargs:
# :return:
# """
# print('执行被装饰函数之前 你可以执行的操作')
# res = func(*args,**kwargs)
# print('执行被装饰函数之后 你可以执行的操作')
# return res
# return inner
#
# @outter # index = outter(最原始的index内存地址)
# def index():
# """
# 这是index函数
# :return:
# """
# pass
#
# print(index)
# print(help(index)) # 查看函数的注释 index是函数名,这个是查看index的注释,修改函数名可以查看别的函数的注释
# print(index.__name__) # 查看函数名字符串形式 打印函数名 字符串
# index()
#
# from functools import wraps
# def outter(func):
# @wraps(func) # 装饰器修复技术
# def inner(*args,**kwargs):
# pass
# return what # 没有定义 所以红
# return inner
# # 装饰器修复技术 两个作用
'''
用户查看被装饰函数的函数名的时候查看到的就是被装饰函数本身
用户查看被装饰函数的注释的时候查看到的就是被装饰函数的注释

'''


'''
多层装饰器经典案例
'''
# def outter1(func1):
# print('加载了outter1')
# def wrapper1(*args,**kwargs):
# print('执行了wrapper1')
# res1=func1(*args,**kwargs)
# return res1
# return wrapper1
# def outter2(func2):
# print('加载了outter2')
# def wrapper2(*args,**kwargs):
# print('执行了wrapper2')
# res2=func2(*args,**kwargs)
# return res2
# return wrapper2
# def outter3(func3):
# print('加载了outter3')
# def wrapper3(*args,**kwargs):
# print('执行了wrapper3')
# res3=func3(*args,**kwargs)
# return res3
# # return wrapper3
# @outter1
# @outter2
# @outter3
# def index():
# print('from index')
# index()

'''
解析:
'''
# @outter1
# index = outter1(wapper2)
'''
第三步,从下往上执行,加载了outter1,将装饰器2的内层函数传入装饰器1,返回装饰器1内层函数
'''
# @outter2 # wrapper2 = outter2(wrapper3)
'''
第二步,从下往上执行,加载了outter2,将装饰器3的内层函数传入装饰器2,返回装饰器2内层函数
'''
# @outter3 # wrapper3 = outter3(最原始的index函数内存地址)
'''
第一步,从下往上执行,加载了outter3,将原函数名index传入装饰器3,返回装饰器3内层函数
'''

"""
加载了outter3,第一步,从下往上执行,加载了outter3,将原函数名index传入装饰器3,返回装饰器3内层函数
加载了outter2,第二步,从下往上执行,加载了outter2,将装饰器3的内层函数传入装饰器2,返回装饰器2内层函数
加载了outter1,第三步,从下往上执行,加载了outter1,将装饰器2的内层函数传入装饰器1,返回装饰器1内层函数

执行了wrapper1,第四步,返回的装饰器1的内层函数赋值给了新函数名,被执行,
即执行装饰器1内层函数,执行打印了wrapper1,继续执行,因为是调用装饰器1时,
传入的参数是装饰器2的内层函数名,装饰器1中的内层函数中的 func = 装饰器2的内层函数,即执行装饰器2的内层函数
执行了wrapper2,第五步,执行装饰器2的内层函数,执行打印了wrapper2,继续执行,因为是调用装饰器2时,
传入的参数是装饰器3的内层函数名,装饰器2中的内层函数中的 func = 装饰器3的内层函数,即执行装饰器3的内层函数
执行了wrapper3 第五步,执行装饰器3的内层函数,执行打印了wrapper3,继续执行,因为是调用装饰器3时,
传入的参数是原函数函数名index,装饰器3中的内层函数中的 func = 原函数函数名index,即执行原函数index
from index
新函数执行完毕
"""













posted on 2019-07-21 11:13  xiaozhen·py  阅读(149)  评论(0编辑  收藏  举报