装饰器>>>前戏>>>高潮(高阶函数和嵌套函数)
装饰器定义:本质是函数,功能是:装饰其他函数。就是为其他函数添加附加功能原则:1.不修改被装饰函数的源代码2.不能修改被装饰的函数的调用方式总结:装饰器对被修饰的函数是完全透明的例题:def timmer(func):def warpper(*args, **kwargs):start_time = time.time()...
装饰器
-
定义:本质是函数,功能是:装饰其他函数。就是为其他函数添加附加功能
-
原则:
1.不修改被装饰函数的源代码 2.不能修改被装饰的函数的调用方式
总结:装饰器对被修饰的函数是完全透明的
例题:
def timmer(func):
def warpper(*args, **kwargs):
start_time = time.time()
func()
stop_time = time.time()
print("the func time is %s" % (stop_time - start_time))
return warpper
def test1():
time.sleep(3)
print("in the test1")
test1()
# 结果是:
# in the test1
再看:
def timmer(func):
def warpper(*args, **kwargs):
start_time = time.time()
func()
stop_time = time.time()
print("the func time is %s" % (stop_time - start_time))
return warpper
@timmer
def test1():
time.sleep(3)
print("in the test1")
test1()
#结果:
# in the test1
# the func time is 3.0004844665527344
可以看出:装饰器本身就是函数,装饰器不修改被装饰函数的源代码,不能修改被装饰的函数的调用方式
实现装饰器需要得知识储备:
-
1.函数就是“变量”
python是解释型语言:定义函数和定义变量是一样的。先将消息体存放在内存中,在调用。只要在调用之前,内存地址里面有函数体。调用的时候就不会报错
下面介绍函数就是“变量”是啥意思:
把pass所代表的函数体,赋值给test变量。定义变量的时候,在内存里找一块地址,存放函数体。(跟变量的概念一样)
python的内存回收机制是解释器做的,当没有变量指向他的时候。
有的函数是不要起名字的叫匿名函数:lambda 匿名函数没有函数名,就会立马被回收掉
calc = lambda x:x * 3
print(calc(3))
#结果:
#9
-
2.高阶函数
满足下面两个条件之一就是高阶函数:
-
1.把一个函数名,当做实参传给另一个函数(在不修改被装饰函数源代码的情况下为其添加功能)
-
2.返回值中包含函数名(不修改函数的调用方式)
(理念就是函数就是“变量”)
-
下面演示,按第一个标准(把一个函数名,当做实参传给另一个函数)定义高阶函数
def bar():
print("in the bar")
def test1(func):
print(func)
test1(bar)
#结果:<function bar at 0x02AC3810>
#结果是内存地址,类似于门牌号。加上小括号是就是调用这个函数
再看:
def bar():
print("in the bar")
def test1(func):
print(func)
func() # func就是函数的门牌号,加上(),就是调用这个函数,类似于func = bar,所以func()就是bar(),可以想变量一样赋值
test1(bar)
# 结果:
# <function bar at 0x00B63810>
# in the bar
# 结果是内存地址,类似于门牌号。加上小括号是就是调用这个函数
再看
def bar():
time.sleep(3)
print("in the bar")
def test1(func):
start_time = time.time()
func() # 运行的是bar函数
stop_time = time.time()
print("the func run time is %s" % (stop_time - start_time)) # test1函数就是给函数附加了一个计时的功能,统计bar的运行时间
test1(bar)
#不能实现装饰器的功能(因为不满足“不能修改被装饰的函数的调用方式”)。至少提供了一种思路:在不修改源代码的情况下,为源代码加上功能。
下面演示按第二个标准(返回值中包含函数名)定义高阶函数:
import time
def bar():
time.sleep(3)
print("in the bar")
def test2(func):
print(func)
return func
print(test2(bar))
#结果
# <function bar at 0x01723810> #print内存地址
# <function bar at 0x01723810> #print打印的返回值
#想法就是:有了内存地址之后,加上括号就是调用函数
test2(bar) #意思是传的内存地址
test2(bar()) #意思是传的bar()的返回值
再看
import time
def bar():
time.sleep(3)
print("in the bar")
def test2(func):
print(func)
return func
t = test2(bar) # 意思是传的内存地址,在test2函数里面在将他返回出来,可以通过变量获取到
print(t) #t变量就是bar的内存地址
#结果
# <function bar at 0x01D83810>
# <function bar at 0x01D83810>
再看
import time
def bar():
time.sleep(3)
print("in the bar")
def test2(func):
print(func)
return func
t = test2(bar) # 意思是传的内存地址,在test2函数里面在将他返回出来,可以通过变量获取到
t() #就代表运行bar这个函数
#结果:
# <function bar at 0x033E3810>
# in the bar
再看
import time
def bar():
time.sleep(3)
print("in the bar")
def test2(func):
print(func)
return func
bar = test2(bar) # 这里相当于用test2加上了新的功能,(print理解为加了很多功能)
bar() #函数的调用方式没有改变。
#结果:
# <function bar at 0x033E3810>
# in the bar
- 3.嵌套函数
定义:在函数的函数体内,用def申明一个新的函数,叫嵌套函数。(而不是去调用别的函数)
嵌套函数的作用域:
import time
def foo():
print("in the foo")
def bar():
print("in the bar")
bar() # 这个函数具有局部变量的特性,再能在内部调用
foo()
#结果:
# in the foo
# in the bar
局部作用域和全局作用域的访问顺序
x = 0
def grandpa():
x = 1
def dad():
x = 2
def son():
x = 3
print(x)
son()
dad()
grandpa()
#结果:3
#从里往外一层一层的找
高阶函数+嵌套函数 才是 装饰器
import time
def deco(func):
start_time = time.time()
func()
stop_time = time.time()
print("the func run time is %s" % (stop_time - start_time))
def test1():
time.sleep(3)
print("in the test1")
def test2():
time.sleep(3)
print("in the test2")
# 思考怎么给test1,test2增加新功能,先写一个高阶函数deco
deco(test1)
deco(test2) # 但是这是在改变函数的调用方式
# 结果:
# in the test1
# the func run time is 3.0005288124084473
# in the test2
# the func run time is 3.000913143157959
# 可以这样:
# 前面一直在使用高阶函数,也可以考虑嵌套函数
再看:
import time
def timer(func): # timer(test1) ,func = test 就是把test1的内存地址传给func
def deco(): # 函数的嵌套。这里就是在内存地址上申明了一个变量
start_time = time.time()
func() # 运行了test1
stop_time = time.time()
print("the func run time is %s" % (stop_time - start_time))
return deco # 高阶函数。这里就是返回了函数的内存地址
def test1():
time.sleep(3)
print("in the test1")
def test2():
time.sleep(3)
print("in the test2")
test1 = timer(test1) # print(timer(test1) )的结果就是deco函数的内存地址
test1() # 执行的是deco,
# 结果:(没有改变test1的源代码,没有改变test1的调用方式。用到函数的嵌套和高阶函数,但是这样做有点麻烦,每次都要运行装饰器,还要赋值给一个变量名一样的变量)
# in the test1
# the func run time is 3.000809669494629
再看:
如果要直接test1()调用,如何实现。
import time
def timer(func): # timer(test1) ,func = test 就是把test1的内存地址传给func
def deco(): # 函数的嵌套。这里就是在内存地址上申明了一个变量
start_time = time.time()
func() # 运行了test1
stop_time = time.time()
print("the func run time is %s" % (stop_time - start_time))
return deco # 高阶函数。这里就是返回了函数的内存地址
@timer # 就等于test1 = timer(test1)
def test1():
time.sleep(3)
print("in the test1")
@timer # 就等于test2 = timer(test1)
def test2():
time.sleep(3)
print("in the test2")
test1()
test2()
#结果:#可以全部选中打断点,查看运行逻辑
# in the test1
# the func run time is 3.0002071857452393
# in the test2
# the func run time is 3.000702381134033
再看:
如果被装饰的函数有参数:
import time
def timer(func):
def deco(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
stop_time = time.time()
print("the func run time is %s" % (stop_time - start_time))
return deco # 高阶函数。这里就是返回了函数的内存地址
@timer # 就等于test1 = timer(test1)
def test1(): # 没有参数
time.sleep(3)
print("in the test1")
@timer # 就等于test2 = timer(test2)
def test2(age): # 有参数
time.sleep(3)
print("test2的参数", age)
test1()
test2(23)
#结果
# in the test1
# the func run time is 3.0001745223999023
# test2的参数 23
# the func run time is 3.000623941421509
decorator就是装饰器的意思,又叫语法糖
有个小需求,某公司的网站有很多页,如果将每个页面定义为一个函数,有些页面需要有权限才能查看
user, passwd = "xf", "4941"
# 写装饰器
def anth(func):
def warpper(*args, **kwargs):
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m") # 加色
func(*args, **kwargs)
else:
exit("\033[31;1mInvalid username or password\033[0m")
return warpper
def index():
print("welcome to index page")
@anth
def home():
print("welcome to home page")
@anth
def bbs():
print("welcome to bbs page")
index()
home()
bbs()
#结果
# welcome to index page
# Username:xf
# Password:4941
# User has passed authentication
# welcome to home page
# Username:xf
# Password:4941
# User has passed authentication
# welcome to bbs page
再看
home()函数有返回值
user, passwd = "xf", "4941"
# 写装饰器
def anth(func):
def warpper(*args, **kwargs):
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m") # 加色
func(*args, **kwargs)
else:
exit("\033[31;1mInvalid username or password\033[0m")
return warpper
def index():
print("welcome to index page")
@anth
def home():
print("welcome to home page")
return "from home"
@anth
def bbs():
print("welcome to bbs page")
index()
print(home())
bbs()
#结果
# welcome to index page
# Username:xf
# Password:4941
# User has passed authentication
# welcome to home page
# None #home()函数的返回值变成空了,因为在装饰器func()里面的返回结果没有赋值给变量
再看:
user, passwd = "xf", "4941"
# 写装饰器
def anth(func):
def warpper(*args, **kwargs):
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m") # 加色
res = func(*args, **kwargs)
print("---after authenticaion") # 随便砸装饰一点东西
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
return warpper
def index():
print("welcome to index page")
@anth
def home():
print("welcome to home page")
return "from home"
@anth
def bbs():
print("welcome to bbs page")
index()
print(home())
bbs()
#结果:
welcome to index page
Username:xf
Password:4941
User has passed authentication
welcome to home page
---after authenticaion
from home #现在就有返回值了
Username:
更多推荐
所有评论(0)