. 装饰器

装饰器是 Python 的重要组成部分。简而言之:它们是修改其他功能的功能。它们有助于使我们的代码更短、更 Pythonic。大多数初学者不知道在哪里使用它们,所以我将分享一些装饰器可以让你的代码更简洁的地方。这可能是最难掌握的概念之一。我们将一步一步地进行,以便您完全理解它。

一. 函数也是对象

首先要搞清楚函数的性质:

def hi(name="yasoob"):return "hi " + nameprint(hi())
# output: 'hi yasoob'# We can even assign a function to a variable like
greet = hi
# We are not using parentheses here because we are not calling the function hi
# instead we are just putting it into the greet variable. Let's try to run thisprint(greet())
# output: 'hi yasoob'# Let's see what happens if we delete the old hi function!
del hi
print(hi())
#outputs: NameErrorprint(greet())
#outputs: 'hi yasoob'eer

结论1:函数可以当对象变量用。

二、在函数中定义函数

因此,这些是功能方面的基础知识。让我们把你的知识更进一步。在 Python 中,我们可以在其他函数中定义函数:

def hi(name="yasoob"):print("now you are inside the hi() function")def greet():return "now you are in the greet() function"def welcome():return "now you are in the welcome() function"print(greet())print(welcome())print("now you are back in the hi() function")hi()
#output:now you are inside the hi() function
#       now you are in the greet() function
#       now you are in the welcome() function
#       now you are back in the hi() function# This shows that whenever you call hi(), greet() and welcome()
# are also called. However the greet() and welcome() functions
# are not available outside the hi() function e.g:greet()
#outputs: NameError: name 'greet' is not defined

所以现在我们知道我们可以在其他函数中定义函数。换句话说:我们可以制作嵌套函数。现在你需要再学习一件事,函数也可以返回函数。

三.从函数内部返回函数:

不必在另一个函数中执行一个函数,我们也可以将其作为输出返回:

def hi(name="yasoob"):def greet():return "now you are in the greet() function"def welcome():return "now you are in the welcome() function"if name == "yasoob":return greetelse:return welcomea = hi()
print(a)
#outputs: <function greet at 0x7f2143c01500>#This clearly shows that `a` now points to the greet() function in hi()
#Now try thisprint(a())
#outputs: now you are in the greet() function

再看一遍代码。在 if/else 子句中,我们返回的是 greet 和welcome,而不是 greet() 和welcome()。这是为什么?这是因为当你在它后面加上一对括号时,函数就会被执行;而如果你不把括号放在它后面,那么它可以被传递并可以分配给其他变量而不执行它。你明白了吗?让我更详细地解释一下。当我们写 a = hi() 时,hi() 会被执行,因为默认名称是 yasoob,所以会返回函数 greet。如果我们将语句更改为 a = hi(name = "ali") 则将返回欢迎函数。我们还可以执行 print hi()() 输出,现在您在 greet() 函数中。

四. 将一个函数作为参数提供给另一个函数

def hi():return "hi yasoob!"def doSomethingBeforeHi(func):print("I am doing some boring work before executing hi()")print(func())doSomethingBeforeHi(hi)
#outputs:I am doing some boring work before executing hi()
#        hi yasoob!

现在,您已经掌握了了解装饰器的真正含义所需的所有知识。装饰器让您可以在函数之前和之后执行代码。

五. 写一个装饰器

在上一个示例中,我们实际上制作了一个装饰器!让我们修改之前的装饰器,制作一个更实用的程序:

def a_new_decorator(a_func):def wrapTheFunction():print("I am doing some boring work before executing a_func()")a_func()print("I am doing some boring work after executing a_func()")return wrapTheFunctiondef a_function_requiring_decoration():print("I am the function which needs some decoration to remove my foul smell")a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
#        I am the function which needs some decoration to remove my foul smell
#        I am doing some boring work after executing a_func()

你明白了吗?我们只是应用了之前学到的原理。这正是装饰器在 Python 中所做的!它们包装一个函数并以一种或另一种方式修改其行为。现在您可能想知道为什么我们没有在代码中的任何地方使用@?这只是组成装饰功能的一种简短方法。下面是我们如何使用 @ 运行前面的代码示例。

@a_new_decorator
def a_function_requiring_decoration():"""Hey you! Decorate me!"""print("I am the function which needs some decoration to ""remove my foul smell")a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
#         I am the function which needs some decoration to remove my foul smell
#         I am doing some boring work after executing a_func()#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

我希望您现在对装饰器在 Python 中的工作方式有一个基本的了解。现在我们的代码有一个问题。如果我们运行:

print(a_function_requiring_decoration.__name__)
# Output: wrapTheFunction

这不是我们所期望的!它的名字是“a_function_requiring_decoration”。好吧,我们的函数被 wrapTheFunction 取代了。它覆盖了我们函数的名称和文档字符串。幸运的是,Python 为我们提供了一个简单的函数来解决这个问题,那就是 functools.wraps。让我们修改之前的示例以使用 functools.wraps:

from functools import wrapsdef a_new_decorator(a_func):@wraps(a_func)def wrapTheFunction():print("I am doing some boring work before executing a_func()")a_func()print("I am doing some boring work after executing a_func()")return wrapTheFunction@a_new_decorator
def a_function_requiring_decoration():"""Hey yo! Decorate me!"""print("I am the function which needs some decoration to ""remove my foul smell")print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration
现在好多了。让我们继续学习装饰器的一些用例。

Blueprint:

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 runningcan_run = False
print(func())
# Output: Function will not run

注意:@wraps 接受一个要装饰的函数,并添加复制函数名称、文档字符串、参数列表等的功能。这允许我们在装饰器中访问预装饰函数的属性。

5.1. 应用

现在让我们看一下装饰器真正闪耀的领域,以及它们的使用使事情变得非常容易管理。下面看看装饰器的管理应用。

5.2. 用于权限管理

装饰器可以帮助检查某人是否被授权使用 Web 应用程序中的端点。它们广泛用于 Flask Web 框架和 Django。这是一个使用基于装饰器的身份验证的示例:

Example :

from functools import wrapsdef requires_auth(f):@wraps(f)def decorated(*args, **kwargs):auth = request.authorizationif not auth or not check_auth(auth.username, auth.password):authenticate()return f(*args, **kwargs)return decorated

5.3. 用于日志管理

日志记录是装饰者大放异彩的另一个领域。这是一个例子:

from functools import wrapsdef 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 + xresult = addition_func(4)
# Output: addition_func was called

我相信你已经在考虑装饰器的一些巧妙用途。

六. 装饰器参数

想一想,@wraps 不也是一个装饰器吗?但是,它需要一个参数,就像任何普通函数一样。那么,为什么我们也不能这样做呢?

这是因为当您使用 @my_decorator 语法时,您正在应用一个将单个函数作为参数的包装函数。请记住,Python 中的一切都是对象,这包括函数!考虑到这一点,我们可以编写一个返回包装函数的函数。

6.1.函数装饰器

让我们回到我们的日志示例,并创建一个包装器,让我们指定要输出到的日志文件。

from functools import wrapsdef logit(logfile='out.log'):def logging_decorator(func):@wraps(func)def wrapped_function(*args, **kwargs):log_string = func.__name__ + " was called"print(log_string)# Open the logfile and appendwith open(logfile, 'a') as opened_file:# Now we log to the specified logfileopened_file.write(log_string + '\n')return func(*args, **kwargs)return wrapped_functionreturn logging_decorator@logit()
def myfunc1():passmyfunc1()
# Output: myfunc1 was called
# A file called out.log now exists, with the above string@logit(logfile='func2.log')
def myfunc2():passmyfunc2()
# Output: myfunc2 was called
# A file called func2.log now exists, with the above string

6.2. 类装饰器

现在我们在生产环境中使用了 logit 装饰器,但是当我们的应用程序的某些部分被认为是关键时,故障可能需要立即引起注意。假设有时您只想登录到文件。其他时候,您希望发送电子邮件,以便引起您的注意,并且仍然保留日志以供您自己记录。这是使用继承的一个例子,但到目前为止我们只看到了用于构建装饰器的函数。

class logit(object):_logfile = 'out.log'def __init__(self, func):self.func = funcdef __call__(self, *args):log_string = self.func.__name__ + " was called"print(log_string)# Open the logfile and appendwith open(self._logfile, 'a') as opened_file:# Now we log to the specified logfileopened_file.write(log_string + '\n')# Now, send a notificationself.notify()# return base funcreturn self.func(*args)def notify(self):# logit only logs, no morepass

这个实现还有一个额外的优点,就是比嵌套函数方法更简洁,并且包装函数仍然会使用与以前相同的语法:

logit._logfile = 'out2.log' # if change log file
@logit
def myfunc1():passmyfunc1()
# Output: myfunc1 was called

现在,让我们将 logit 子类化以添加电子邮件功能(尽管此处不会涉及此主题)。

class email_logit(logit):'''A logit implementation for sending emails to adminswhen the function is called.'''def __init__(self, email='admin@myproject.com', *args, **kwargs):self.email = emailsuper(email_logit, self).__init__(*args, **kwargs)def notify(self):# Send an email to self.email# Will not be implemented herepass

从这里开始,@email_logit 的工作方式与 @logit 类似,但除了记录日志外,还会向管理员发送一封电子邮件。

python语言:装饰器原理相关推荐

  1. python装饰器原理-Python函数装饰器原理与用法详解

    本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...

  2. python property装饰器原理,Python @property装饰器不起作用

    Could anyone find a problem with this @property decorator? I cannot seem to get it to assert correct ...

  3. python function at 0x00000_Python函数装饰器原理与用法详解

    本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...

  4. python中装饰器的作用_Python装饰器详解,详细介绍它的应用场景

    装饰器的应用场景附加功能 数据的清理或添加:函数参数类型验证 @require_ints 类似请求前拦截数据格式转换 将函数返回字典改为 JSON/YAML 类似响应后篡改为函数提供额外的数据 moc ...

  5. python装饰器原理-深刻理解python装饰器

    我们要完全理解python装饰器,不是很容易,主要归结有如下困难: 1. 关于函数"变量"(或"变量"函数)的理解 2. 关于高阶函数的理解 3. 关于嵌套函数 ...

  6. python装饰器原理-Python装饰器原理

    装饰器(Decorator)是面向对象设计模式的一种,这种模式的核心思想是在不改变原来核心业务逻辑代码的情况下,对函数或类对象进行额外的修饰.python中的装饰器由python解释器直接支持,其定义 ...

  7. python装饰器原理-深入理解 Python 装饰器

    作者简介 曾凡伟,携程信息安全部高级安全工程师,2015年加入携程,主要负责安全自动化产品的设计和研发,包括各类扫描器.漏洞管理平台.安全 SaaS 平台等. Python 是一门追求优雅编程的语言, ...

  8. python装饰器原理-Python装饰器原理与用法分析

    这篇文章主要介绍了Python装饰器原理与用法,结合实例形式分析了Python装饰器的概念.原理.使用方法及相关操作注意事项,需要的朋友可以参考下 本文实例讲述了Python装饰器原理与用法.分享给大 ...

  9. python装饰器原理-Python装饰器的实现原理

    Python中的装饰器是通过利用了函数特性的闭包实现的,所以在说装饰器之前,我们需要先了解函数特性,以及闭包是怎么利用了函数特性的. 1.函数特性 Python中的函数特性总的来说有四点: 1.函数作 ...

  10. python装饰器原理-简单了解python装饰器原理及使用方法

    这篇文章主要介绍了简单了解python装饰器原理及使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 如果你接触 Python 有一段时间了的话 ...

最新文章

  1. python和对象复习_【Python复习巩固 Day4】面向对象编程
  2. 第十二章_请求和响应的装饰
  3. 创建存储过程时出现的This function has none of DETERMINISTIC, NO SQL解决办法
  4. spring mvc学习(44):springMVC运行原理
  5. oracle重建orainventory,数据库重建oraInventory
  6. 朋友圈设置成昨天发的_如何让你的朋友圈骚到脱颖而出?
  7. AcWing基础算法课Level-2 第六讲 贪心
  8. pyRedis - 操作指南:增/删/改/查、管道与发布订阅功能
  9. crmeb java单商户源码java二开文档部署文档H5商城部署文档【5】
  10. nginx的安装升级、常用配置(一)
  11. FormData 对象上传二进制文件
  12. window10突然变成繁体怎么办呢??
  13. MYSQL学习思维导图
  14. 一个隐藏android应用图标的方法
  15. 照片和木马合成一张照片
  16. XiaoHu日志 6/3~6/5
  17. 深入理解JVM - ZGC垃圾收集器
  18. 富爸爸与穷爸爸读书笔记
  19. 百度AI技术「通用物体与场景识别」开发使用体验
  20. Generalizing to Unseen Domains: A Survey on Domain Generalization 论文分享

热门文章

  1. 机器学习笔记: 聚类 模糊聚类与模糊层次聚类(论文笔记 Fuzzy Agglomerative Clustering :ICAISC 2015)
  2. 文巾解题 面试题 01.03. URL化
  3. 文巾解题 1744. 你能在你最喜欢的那天吃到你最喜欢的糖果吗?
  4. Linux下如何查看系统启动时间和运行时间
  5. mysql语句导出数据库文件_通过Mysql命令行语句来导入、导出数据库文件
  6. 农历法定日历_木瓜日历安卓版下载-木瓜日历V1.5下载
  7. 安装libtiff包 Python3
  8. Python pandas dataframe 分组聚合时,分组组名并入列的方法
  9. 使用flink Table Sql api来构建批量和流式应用(1)Table的基本概念
  10. Lambda架构在有赞广告平台的应用与演进