python装饰器理解,小盒子,中盒子,大盒子

编程入门 行业动态 更新时间:2024-10-15 18:28:54

python装饰器理解,小<a href=https://www.elefans.com/category/jswz/34/1770108.html style=盒子,中盒子,大盒子"/>

python装饰器理解,小盒子,中盒子,大盒子

“”"
装饰器目的是在不改变待装饰函数代码的情况下,增加额外的
功能,装饰器的返回值是已装饰的函数对象
“”"

假设有代码:

import time
def test():time.sleep(2)print("test is running!")
test()

很显然,这段代码运行的结果一定是:等待约2秒后,输出

“”"
高阶函数
那么对于高阶函数的形式可以有两种:

1.把一个函数名当作实参传给另外一个函数(“实参高阶函数”)
2.返回值中包含函数名(“返回值高阶函数”)
“”"

“”"
那么这里面所说的函数名,实际上就是函数的地址,也可以认为是函数的一个标签而已,
并不是调用,是个名词。如果可以把函数名当做实参,那么也就是说可以把函数传递到另一个函数,
然后在另一个函数里面做一些操作,根据这些分析来看,这岂不是满足了装饰器三原则中的第一条,
即不修改源代码而增加功能。那我们看来一下具体的做法:
“”"

import time
def test():time.sleep(2)print("test is running!")def deco(func):start = time.time()func()  # 2stop = time.time()print(stop - start)
deco(test)  # 1

“”"
我们来看一下这段代码,在#1处,
我们把test当作实参传递给形参func,即func=test。
注意,这里传递的是地址,也就是此时func也指向了之前test所定义的那个函数体,
可以说在deco()内部,func就是test。在#2处,把函数名后面加上括号,就是对函数的调用(执行它)。
因此,这段代码运行结果是:
test is running!
the run time is 3.0009405612945557
“”"

“”"
我们看到似乎是达到了需求,即执行了源程序,
同时也附加了计时功能,但是这只满足了原则1(不能修改被装饰的函数的源代码),
但这修改了调用方式。假设不修改调用方式,那么在这样的程序中,
被装饰函数就无法传递到另一个装饰函数中去。

那么再思考,如果不修改调用方式,就是一定要有test()这条语句,那么就用到了第二种高阶函数,即返回值中包含函数名
“”"

import timedef test():time.sleep(2)print("test is running!")def deco(func):print(func)return funct = deco(test)  # 3

t()#4

test()

“”“进化版”""

import timedef timer(func):# 5def deco():start = time.time()func()stop = time.time()print(stop - start)return decotest = timer(test)  # 6
def test():time.sleep(2)print("test is running!")
test()  # 7

“”"
这段代码可能会有些困惑,怎么忽然多了这么多,暂且先接受它,分析一下再来说为什么是这样。
首先,在#6处,把test作为参数传递给了timer(),此时,在timer()内部,func = test,接下来,
定义了一个deco()函数,当并未调用,只是在内存中保存了,并且标签为deco。在timer()函数的最后返回deco()的地址deco。
然后再把deco赋值给了test,那么此时test已经不是原来的test了,也就是test原来的那些函数体的标签换掉了,换成了deco。
那么在#7处调用的实际上是deco()。

那么这段代码在本质上是修改了调用函数,但在表面上并未修改调用方式,而且实现了附加功能。
那么通俗一点的理解就是:

把函数看成是盒子,test是小盒子,deco是中盒子,timer是大盒子。
程序中,把小盒子test传递到大盒子temer中的中盒子deco,然后再把中盒子deco拿出来,打开看看(调用)
“”"

“”"
3、 真正的装饰器
根据以上分析,装饰器在装饰时,需要在每个函数前面加上:
test = timer(test)
显然有些麻烦,Python提供了一种语法糖,即:
@timer
“”"

“”“实例”""

# def dec(f):
#     n = 3
#     def wrapper(*args, **kw):
#         return f(*args, **kw) * n
#     return wrapper
#
#
# @dec
# def foo(n):
#     return n * 2
#
# print(foo(2))# 装饰器有参数
# import time
#
# def timer(func):
#     def deco():
#         start = time.time()
#         func()
#         stop = time.time()
#         print(stop-start)
#     return deco
#
# @timer
# def test(parameter): #8
#     time.sleep(2)
#     print("test is running!")
# test()

“”"
对于一个实际问题,往往是有参数的,如果要在#8处,给被修饰函数加上参数,显然这段程序会报错的。
错误原因是test()在调用的时候缺少了一个位置参数的。而我们知道test = func = deco,因此test()=func()=deco()
,那么当test(parameter)有参数时,就必须给func()和deco()也加上参数,
为了使程序更加有扩展性,因此在装饰器中的deco()和func(),加如了可变参数*agrs和 **kwargs。
“”"

import timedef timer(func):def deco(*args, **kwargs):start = time.time()func(*args, **kwargs)stop = time.time()print(stop-start)return deco@timer
def test(parameter): #8time.sleep(2)print("test is running!")
test()

“”"
带返回值
“”"

import timedef timer(func):def deco(*args, **kwargs):start = time.time()res = func(*args, **kwargs)stop = time.time()print(stop-start)return resreturn deco@timer
def test(parameter): #8time.sleep(2)print("test is running!")return "Returned value"
test()

总结:

1, 把函数看成是盒子,test是小盒子,deco是中盒子,timer是大盒子。
程序中,把小盒子test传递到大盒子temer中的中盒子deco,然后再把中盒子deco拿出来,打开看看(调用)‘

2, 根据以上分析,装饰器在装饰时,需要在每个函数前面加上:
test = timer(test)
显然有些麻烦,Python提供了一种语法糖,即:
@timer’

更多推荐

python装饰器理解,小盒子,中盒子,大盒子

本文发布于:2024-02-11 16:45:45,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1682075.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:盒子   小盒子   python

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!