基础入门8---装饰器

一. 装饰器(也叫装饰器函数)
1) 作用域 local/enclosing/global/built-in (LEGB)
x=5
def f_outer():
y=7
def f_inner():
global x # x引用哪一层就用哪一层的作用域,本次引用的全局作用域的变量,就把x=5引用进来了
z=3
x=x+1
print(x) >>> 6
return 11
f_inner()
f_outer()


x=5
def f_outer():
y=7
def f_inner():
nonlocal y >>># 内部局部作用域引用外部变量y=7
y=y+2
print(y) >>> 9
return 11
f_inner()
f_outer()


2) 高阶函数
a)函数名可以作为参数输入
b)函数名可以返回值

x=9
def outer():
def inner():
print(x) >>>9
return inner
outer()()

def outer():
x=11
def inner():
nonlocal x
x=x+5
print(x) >>>16 #高阶函数两个特点,一是函数名可以作为变量使用,二是函数可以作为返回值使用
return inner
outer()()

3)闭包
定义: 如果在一个内部函数里,对在外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就认为是一个闭包(closure)
def outer():
x=10
def inner():
print(x) >>>10
return inner
outer()() >>># 第一步先通过outer()启动函数调用,将X=10,及返回值inner 存在内存中。
第二步再通过第二个(),相当于通过inner()格式将内部inner()函数启动,打印出X的值(X这个时候只能看,不用改)

def outer():
x=10
def inner(): #条件一,一个内部函数
nonlocal x
print(x) >>>10 #条件二,对外部作用域X进行引用
x=x+1
print(x) >>>11
return inner # 结论,内部函数就是一个闭包(闭包就是脱离内部调用,可以在外部调用执行内部函数)
outer()()


def outer(a):
def inner():
print(a) >>>10 # 外部环境变量10通过调用传入函数体内
return inner
outer(10)()

上例实践说明,当调用外部函数outer()时,只会执行外部函数,内部函数一定要同时再调用inner()才会执行内部函数。但是由于闭包的存在(两个
条件,一个是内部函数,第二个对外部作用域变量的x的引用,形成了闭包),这个时候就可以脱离内部调用命令,在外部函数中调用内部函数并执行。
否则的话,按照作用域范围 ,局部变量在全局范围下是不能调用

4. * 代码的开放,封闭原则
所谓的开放封闭原则,就是对修改封闭,对扩展开放。

import time # 调用时间模块
start_time=time.time() # time.time(),这个是一个时间戳(时间是从1970年,1月1号开始到现在的秒数,1970/1/1是linux系统誔生的时间)
print('OK,time is over')
time.sleep(3) # 这个是模拟时间停止3秒
end_time=time.time() #这个当前结束时间
print(end_time-start_time) >>> 3.000171422958374 开始时间与结束时间相减,得到时间差

import time #调用时间模块
print(time.strftime('%Y-%m-%d %X')) #当前时间显示(格式自定) >>> 2020-04-20 16:55:18
print(time.time()) # 当前时间戳1587372918.7721689


import time
def f():
start_time=time.time()
print('very good...') >>> very good...
time.sleep(3)
end_time=time.time()
print('运行时间%s秒'%(end_time-start_time)) >>> 运行时间3.000171661376953秒
f()

5.装饰器的实例应用
import time
def do_func():
start_time=time.time()
print('very good...') >>> very good...
time.sleep(3.3)
end_time=time.time()
print('代码运行时间:%s'%(end_time-start_time)) >>> 代码运行时间:3.30720591545105
do_func()

def do_play():
start_time = time.time()
print('too slow...') >>>too slow...
time.sleep(2.7)
end_time = time.time()
print('代码运行时间:%s' % (end_time - start_time)) >>> 代码运行时间:2.714404582977295
do_play()

import time
def do_func():
print('very good...')
time.sleep(3.3)
def do_play():
print('too slow...')
time.sleep(2.7)
def show_time(f):
start_time = time.time()
f()
end_time = time.time()
print('代码运行时间:%s' % (end_time - start_time))
show_time(do_func)
show_time(do_play)

-----***-----
import time
def do():
print('go on sth...')
time.sleep(2.68)

def time_calculate():
start_time = time.time()
do() #将需要计算do()代码代入在这里,这样就完成了封闭开放的原则,另起一个函数对原do函数不动,用
end_time = time.time() 新的函数time_calculate对原do函数进行扩展计算
print(end_time - start_time)
time_calculate() #启动计算时间函数,完成上一个函数体的时间计算

-----***----
import time
def do():
print('go on sth...')
time.sleep(2.68)
def fighting():
print('fighting...')
time.sleep(3.21)

def time_calculate(f): # 形参传入了do,fighting两个功能函数名
start_time = time.time()
f() #采用动态的模式,将调用的函数名,通过实参,形参传入函数体内并执行
end_time = time.time()
print(end_time - start_time)
time_calculate(do) #实参调入启动do函数
time_calculate(fighting) #实参调入启动fighting函数

----***------
import time
def do():
print('go on sth...')
time.sleep(2.68)
def fighting():
print('fighting...')
time.sleep(3.21)

def time_calculate(f):
def inner():
start_time = time.time()
f()
end_time = time.time()
print(end_time - start_time)
return inner

do=time_calculate(do)
fighting=time_calculate(fighting)
do() #>>> time_calculate(do)
fighting() #>>>time_calculate(fighting)

以上通过内嵌函数(重要点),返回一个inner值,再将do,fighting两个值赋给time_calculate(do)及time_calculate(fighting)
再加花括号,就可以使用原来的执行方式进行调动函数。就实现了不作任何改动,扩展功能加上去。

----***-----
在python中为了解决更好的解决赋值问题采用了更好的一个结构模式的语法糖
import time
def time_calculate(f):
def inner():
start_time = time.time()
f()
end_time = time.time()
print(end_time - start_time)
return inner

@time_calculate #此处加入语法糖 @ / @time_calcuate等于>>> do== time_calculate(do)相当于上面中的赋值操作
def do():
print('go on sth...')
time.sleep(2.68)
do() # 启动函数时同时原函数与上面扩展函数同时运行

@time_calculate #此处加入语法糖 @ /@time_calcuate等于>>> do== time_calculate(fighting)相当于上面中的赋值操作
def fighting():
print('fighting...')
time.sleep(3.21)
fighting() # 启动函数时同时原函数与上面扩展函数同时运行

-------------***-----------
import time
def firm_doing(fro): #调整一下结构位置,将扩展函数放在运行函数体的上层
def inner(): # 嵌套一个内部函数(重要点)返回一个inner值,这样@就起作用了同时调动
start_time=time.time()
fro() #动套的将实参中的函数传入到内部作用域中
end_time=time.time()
print('确认时间%s'%(end_time-start_time))
return inner

@firm_doing # @firm_doing语法糖=firm_doing(func1) 语法糖作用同时启动两个函数
def func1():
print('我们学习5秒钟...')
time.sleep(5)
func1()

@firm_doing # @firm_doing语法糖=firm_doing(func1),语法糖作用同时启动两个函数
def func2():
print('我们运动3秒钟...')
time.sleep(3)
func2

运行的结果:
我们学习5秒钟...
确认时间5.007608652114868
我们运动3秒钟...
确认时间3.010805606842041

------------***--------------------------
import time
def z(a):
def inner():
start=time.time()
a()
end=time.time()
print('此程序过程时间%s'%(end-start))
return inner

@z #x=z(x)
def x():
print('读书功能')
time.sleep(2.22)
x()

@z #y=z(y)
def y():
print('写字功能')
time.sleep(1.65)
y()

6.装饰器中参数的传递
a.功能函数加参数(f2)
import time
def count(n): # 将f2函数传入,得到inner并启动inner(3,8)函数将3,8数据再传入内层inner函数中
def inner(x,y):
start=time.time()
n(x,y) #得到f2(3,8)>>>11
time.sleep(1.2)
end = time.time()
print('spend%s'%(end-start)) >>>spend1.200068473815918
return inner

@count # f2=count(f2)
def f2(a,b):
print(a+b)
f2(3,8)

b.装饰器加入参数

import time
def time_logger():
time_format='%Y-%m-%d %X'
currency_time=time.strftime(time_format)
print(currency_time)

def logger(flag): #外层第三层函数的目的,是将'flay==True'传入函数体中备用
def count(n):
def inner(x,y):
start=time.time()
n(x,y) >>>11
time.sleep(1.2)
end = time.time()
print('spend%s'%(end-start)) >>> spend1.200068473815918
if flag=='True':
time_logger() >>>2020-05-04 14:58:16
return inner
return count

@logger('True') # 相当于把logger中的‘True'参数传入函数体中,并返回一个count,再加上@就等于@count就等于f2=count(f2)>>>f2()=count(f2)()把f2再传入函数体中
def f2(a,b): 并返回inner,再将3,8传入到inner(3,8)中进行运算
print(a+b)
f2(3,8)

小结,在装饰器中添加参数,就会出现三层嵌套,最外面一层的嵌套目的是将要用的参数传入内存中备用,再加上内层加上
一个判断条件来满足该参数是否需要调用,同时外层语法糖@与外层的返回值合并再构中间层与内层的调用模式@

import time
def print_need(flag):
def f_original(f):
def inner():
time_format='%Y-%m-%d %X'
logger=time.strftime(time_format)
print(logger)
start_time=time.time()
f()
if flag=='true':
print('完成')
else:
print('不需要')
end_time=time.time()
print(end_time-start_time)
return inner
return f_original

@print_need('true') #等于一把‘true'传入函数体中’,二与返回值合成@f_original此又等于do=f_original(do)
def do():
print('读书功能...')
time.sleep(1.3)
do()

@print_need('false') #等于一把‘false'传入函数体中’,二与返回值合成@f_original此又等于do=f_original(play)
def play():
print('玩耍功能')
time.sleep(2.2)
play()

------------***-------------------------------
import time
def f_all(n):
def time_check(f):
def inner():
start=time.time()
f() >>>读书功能。。。
name=input('name:>>>') >>>wangwei
if n==3:
print('你猜对了') >>>你猜对了
end=time.time()
print(end-start) >>> 9.094815969467163
return inner
return time_check

@f_all(3) #先用f_all(3),将3的数据传入内存中备用,并返回一个time_check值,结合@并成一个@time_check,
#而@time_check等同于func1=time_check(func1),再将启动内层函数并将func1传入函数体中
def func1():
print('读书功能。。。')
func1()

@f_all(3)
def func2():
print('写作功能。。。')

posted @ 2020-05-06 08:55  fother  阅读(119)  评论(0)    收藏  举报