⼈⼈都能看懂的Python装饰器⼊门教程!
⼤家好,我是涛哥。
之前的⽂章中提到,很多⼈认为理解了装饰器的概念和⽤法后,会觉得⾃⼰的 Python ⽔平有⼀个明显的提⾼。
但很多教程在⼀上来就会给出装饰器的定义以及基本⽤法,例如你⼀定会在很多⽂章中看到例如代码运高中信息数据类型分类
⾏时间计时器等相关常⽤装饰器。
直接从应⽤⼊⼿这样学习当然⼗分有效,但不是看过就忘就是似懂⾮懂的状态,因为装饰器从来就不是⼀个单独的概念,就像数学分析中求积分⼀样,你可以通过公式快速算出需要求的积分,但是若明⽩积分是由极限定义的,之后再看积分将会是不⼀样的视⾓。
本⽂我将尝试说清楚为什么需要现装饰器、什么是装饰器、以及如何写⼀个简单的装饰器,但要彻底理解装饰器还要从函数开始说起,下⾯是有关函数的四个重要的概念,希望⼤家可以明⽩。
01
有关函数的四个重要概念
相信你在⼤多数⽂章中,⾄少也能知道例如「装饰器是装饰函数」,「在不修改函数代码的情况下增加额外功能」等核⼼概念,但⾸先要知道为什么函数能够被装饰。
例如在《流畅的Python》⼀书中,讲到函数的⼀开始就提出了⼀个概念,函数是⼀等对象
正如书中所说,在Python中⼀个函数既可以作为参数被传递,也能作为另⼀个函数的返回值,这也是函数可以被装饰的关键,在介绍装饰器之前,下⾯有必要通过简单的代码对这段话做⼀个更直观的理解。
1.1 函数中传递函数python入门教程下线阅读
函数中传递函数意思就是可以将函数当作变量来使⽤,我们来看⼀个简单的⽰例。
在下⾯的代码中,func1是⼀个普通的函数,接受两个参数a,b并返回他们的和。func2不⼀样的地⽅在于多接收了⼀个func参数,这个func变量需要是⼀个函数
def func1(a,b):
print(f"函数 {func1.__name__} 正在执⾏")
return a + b
def func2(func,c,d):
print(f"函数 {func2.__name__} 正在执⾏")
return func(c,d)
现在让我们来执⾏func1
函数 func1 正在执⾏
3
下⾯func1作为参数执⾏func2
>>> func2(func1,3,4)
函数 func2 正在执⾏
函数 func1 正在执⾏
7
可以看到,先执⾏func2,在func2接收到fun1后,再次执⾏func1并返回。注意这⾥的func1没有括号,它只不过是和a,b⼀样的参数被使⽤,理解这点后我们继续看下⼀个知识点。
1.2 函数中定义函数代码生成网站
在定义⼀个函数后,可以继续在函数内部定义新的函数。为了理解这点,我们来看下⾯简单的⽰例。
我们先定义了⼀个函数func1,并在func1中定义了func2,并在func1的内部调⽤了func2
def func1():
print(f"函数 {func1.__name__} 正在执⾏")
def func2():
print(f"内部函数 {func2.__name__} 正在执⾏")
func2()
现在执⾏func1与func2看看会发⽣什么
>>> func1()
函数 func1 正在执⾏
内部函数 func2 正在执⾏
>>> func2()
------------------------------------------------
Traceback (most recent call last)
----> 1 func2()
NameError: name 'func2' is not defined
可以看到,当执⾏func1时,会⾃动执⾏func2,但是如果单独执⾏func2,则提⽰未定义,说明func2只能在func1中被调⽤!
1.3 函数返回函数
最后是⼀个函数可以将另⼀个函数作为返回值返回的简单⽰例,在下⾯的代码中,我们先定义了⼀个外部函数func1(接受⼀个参数a),之后定义了⼀个内部函数func2(接受⼀个参数b)并返回a + b,最后将func2作为func1的返回值返回
print(f"函数 {func1.__name__} 正在执⾏")
def func2(b):
print(f"函数 {func2.__name__} 正在执⾏")
return a + b
return func2
需要注意的是,这⾥返回的func2没有括号,代表返回的是func2的地址!
>>> func3 = func1(1)
>>> func3
函数 func1 正在执⾏
<function __main__.func1.<locals>.func2(b)>
>>> func3(2)
函数 func2 正在执⾏
3
从上⾯的运⾏结果可以看到,当执⾏func1(1)后,返回的是func2的地址,并赋给func3,之后执⾏func3(2)才真正执⾏了内部函数func2!
现在我们就解决了上⼀⼩节的问题「将内部函数func2单独拿出来⽤」!
1.4 函数内省
函数内省是相对来说⽐较好理解的⼀个概念,在Python中的意思就是我们可以访问函数的部分属性,例如print函数,可以使⽤dir函数来查
看其全部属性
>>> dir(print)
['__call__',
'__class__',
'__delattr__',
··· ···
'__subclasshook__',
'__text_signature__']
现在可以查看其对应的属性
>>> print.__name__java常用加密算法
'print'
>>> print.__call__
<method-wrapper '__call__' of builtin_function_or_method object at 0x7fddb8056b80>
>>> print.__doc__
"print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n\nPrints the values to a stream, or to sys.stdout by default.\nOptional keyword arguments:\nfile: a 函数内省了解到这个程度即可,我们会在2.3节再次提到这⾥的知识!
⾄此,我已经将接触装饰器之前必须要吃透的知识点介绍完毕,如果你觉得我讲解的不够清晰,可以查看任何其他教程或者书籍弄懂后再继续阅读。
02
c strlen函数初识装饰器
现在终于可以来说说装饰器了,当然绝对不是直接告诉你⼀个写好的装饰器,⽽是我们⼀点⼀点去写⼀个简单的装饰器。
2.1 第⼀个装饰器
在下⾯的代码中,我们先定义了⼀个函数first_decorator,该函数接受函数为参数(如果不理解请查看本⽂ 1.1 节),之后在内部定义了⼀个名为name_wrapper的内部函数(如果不理解请查看本⽂ 1.2 节),最后返回以name_wrapper作为返回值(如果不理解请查看本⽂ 1.3节)
def first_decorator(func):
def name_wrapper():
print(f"被装饰的函数 {func.__name__} 即将执⾏")
func()
print(f"被装饰的函数 {func.__name__} 执⾏完毕")
return name_wrapper
这个函数的功能是,在执⾏被接收函数前后分别打印⼀段话,所以我们要再定义⼀个函数来测试效果
def add():
print("函数 add 正在执⾏ ")
这个fun1没有什么好说的,打印⼀段话。下⾯需要仔细看了,我们来执⾏这两段代码
>>> add = first_decorator(add)
>>> add()
被装饰的函数 add 即将执⾏
函数 add 正在执⾏
被装饰的函数 add 执⾏完毕
正如我们预料的⼀样,在执⾏add前后都有⼀段提⽰,但是如果每次使⽤first_decorator功能都需要先将add传递,之后再调⽤,来回写好⼏遍,实在太⿇烦了!
因此这完全有更Pythonic的写法,也就是我们常见的装饰器形式,使⽤语法糖@,例如上⾯的例⼦和下⾯的写法等价
@first_decorator
def add():
print("函数 add 正在执⾏ ")
⽤@+装饰器函数名字放在需要被装饰函数的上⽅即可,现在直接调⽤add即可实现装饰器的功能!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论