装饰器
本文正在参加「Python主题月」,详情查看活动链接
装饰器是 Python 的重要组成部分。简而言之:它们是修改其他函数功能的函数。大多数初学者不知道在哪里使用它们,所以我将分享一些装饰器可以使您的代码更简洁。
首先,让我们讨论如何编写自己的装饰器。
这可能是最难掌握的概念之一。我们将一步一步来,以便您能够完全理解它。
1. Python 中的一切都是一个对象:
首先让我们了解Python中的函数:
def test(name="dm"):
return "你好 " + name
print(test())
>>> '你好 dm'
2. 在函数中定义函数:
所以这些是功能的基础。让我们进一步了解您的知识。在 Python 中,我们可以在其他函数中定义函数:
def test(name="dm"):
print("我是111")
def inside1():
return "inside11"
def inside2():
return "inside22"
print(inside1())
print(inside2())
test()
>>> 我是111
inside11
inside22
inside1() # 不能在外面直接调用里面的函数
>>> NameError: name 'inside1' is not defined
所以现在我们知道我们可以在其他函数中定义函数。换句话说:我们可以创建嵌套函数。现在你需要学习一件事,函数也可以返回函数。
3. 从函数内部返回函数:
没有必要在另一个函数中执行一个函数,我们也可以将它作为输出返回:
def test(name="dm"):
def inside1():
return "inside11"
def inside2():
return "inside22"
if name == "dm":
return inside1
else:
return inside2
a = hi()
print(a)
>>> <function inside1 at 0x7f21e36594>
print(a())
>>> inside11
在if/else
子句中,我们返回inside1
和 inside2
,而不是inside1()
和 inside2()
。这是为什么?这是因为当你在它后面加上一对括号时,函数就会被执行;而如果你不在它后面加上括号,那么它可以被传递并且可以分配给其他变量而不执行它。
4. 将一个函数作为另一个函数的参数:
def test():
return "hi boy!"
def inner(func):
print("inner1")
print(func())
inner(test)
>>> inner1
hi boy!
现在你已经掌握了所有必要的知识来了解什么是装饰器。装饰器让你在函数前后执行代码。
5. 编写你的第一个装饰器:
在上一个例子中,我们实际上做了一个装饰器!让我们修改之前的装饰器并制作一个更有用的程序:
def outside(func):
def inner():
print("inner1")
func()
return inner
def abc():
print("hihihihi")
abc()
>>> "hihihihi"
a = outside(abc)
a()
>>> inner1
hihihihi
我们只是应用了之前学到的原则。这正是装饰器在 Python 中所做的!他们包装一个函数并以一种或另一种方式修改它的行为。现在您可能想知道为什么我们没有在代码中的任何地方使用 @?这只是组成装饰函数的一种简短方法。下面是我们如何使用 @ 运行前面的代码示例。
@outside
def abc():
print("hihihihi")
a = outside(abc)
a()
>>> inner1
hihihihi
现在好多了。让我们继续学习一些装饰器的用例。
示例
from functools import wraps
def decorator_name(f):
@wraps(f)
def decorated(*args, **kwargs):
if not can_run:
return "Function will not run"
return f(*args, **kwargs)
return decorated
@decorator_name
def func():
return("Function is running")
can_run = True
print(func())
>>> Output: Function is running
can_run = False
print(func())
>>> Output: Function will not run
注意:@wraps
接受要装饰的函数并添加复制函数名称、文档字符串、参数列表等的功能。这允许我们在装饰器中访问预装饰函数的属性。
5.1. 用例:
现在让我们来看看装饰器真正发挥作用的领域,它们的使用使得一些东西非常容易管理。
5.2. 授权
装饰器可以帮助检查某人是否被授权使用 Web 应用程序中的端点。它们广泛用于 Flask Web 框架和 Django。这是使用基于装饰器的身份验证的示例:
例子 :
from functools import wraps
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated
5.3. 日志记录
日志是装饰器发光的另一个领域。下面是一个例子:
from functools import wraps
def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
result = addition_func(4)
# Output: addition_func was called
我相信你已经在考虑装饰器的一些巧妙用途。
装饰器条件:
1.外部函数中定义了内部函数
2.外部函数一定要有返回值,返回的值是:内部函数名
3.内部函数引用了外部函数的变量
4.函数作为外层函数参数
使用装饰器:
@装饰器名字
def 函数名():
pass
-
简单的装饰器
在闭包的前提下引用函数作为外层函数的参数
import time # 装饰器带参数 def zhuang1(func): # 接收f1函数作为参数 def wrapper(*args, **kwargs): # 这里就要加*args,**kwargs 1.外部函数中定义了内部函数 print("正在校验中.....") time.sleep(2) print("校验完毕.....") func(*args, **kwargs) # 调用原函数f1 4.函数作为外层函数参数 return wrapper # 把装饰器在返回给f1 2.外部函数一定要有返回值,返回的值是:内部函数名 @zhuang1 def f1(): print("我是户主one------one") f1()
-
带有参数的函数
import time # 装饰器带参数 def zhuang1(func): # 接收f1 def wrapper(*args, **kwargs): # 这里就要加*args,**kwargs print("正在校验中.....") time.sleep(2) print("校验完毕.....") # 调用原函数 func(*args, **kwargs) return wrapper # 把装饰器在返回给f1 sum = 10000 @zhuang1 def f1(sum): print("我是户主one------one", sum) f1(sum) @zhuang1 def f2(sum, name="abc"): print("我是户主{}-----two".format(name), sum) f2(sum) @zhuang1 def f2(sum, name="aaaaaa"): print("我是户主{}-----two".format(name), sum) f2(sum, name="adfafasdasd") # 覆盖了name的值
-
装饰的函数有返回值
一定要返回原函数
# 如果装饰的函数有返回值需要在装饰器的内部函数中用return返回 装饰函数的运行结果 def say(func): def inner(): print("-----2-----") return func() # 这里一定要返回原函数 return inner @say def show(): return "-----1-----" print(show())
-
使用多个装饰器装饰同一个函数
''' 如果装饰器是多层的,谁距离函数最近就优先使用哪个装饰器 ''' def zhuangfeng1(func): # 定义装饰器1 print("-----one---start") def warper(): print("刷漆..") return func() # 返回原函数 print("end") return warper def zhuangfeng2(func): # 定义装饰器2 print("-----two---start") def warper(): print("打麻椒..") return func() # 返回原函数 print("end") return warper # 使用装饰器 @zhuangfeng2 @zhuangfeng1 def fz1(): return "户主一" print(fz1()) """ -----one---start end -----two---start end 打麻椒.. 刷漆.. 户主一 """ #总结:多个装饰器作用于同一个函数的时候,从上往下依次执行,但是,原函数只被调用一次
-
装饰器带有参数
有三层
''' 装饰器带参数 带参数的装饰器是三层的 第一层: 负责接收装饰器的参数 第二层: 负责接收函数 第三层: 去接收函数里面的参数 ''' def outer(a): # 第一层: 负责接收装饰器的参数 def decorate(func): # 第二层: 负责接收函数 def wraper(*args, **kwargs): # 第三层: 去买个接收函数的参数 func(*args, **kwargs) print("--->铺地砖{}块".format(a)) return wraper return decorate @outer(100) # 装饰器带有参数 def house(time): print("我{}日期拿到了毛坯房".format(time)) house("2020-9-9")