python 装饰器重要在哪


Posted in Python onFebruary 14, 2021

1.什么是装饰器?

要理解什么是装饰器,您首先需要熟悉Python处理函数的方式。从它的观点来看,函数和对象没有什么不同。它们有属性,可以重新分配:

def func(): 
 print('hello from func') 
func() 
> hello from func 
new_func = func 
new_func() 
> hello from func 
print(new_func.__name__) 
> func

此外,你还可以将它们作为参数传递给其他函数:

def func(): 
 print('hello from func') 
def call_func_twice(callback): 
 callback() 
 callback() 
call_func_twice(func) 
> hello from func 
> hello from func

现在,我们介绍装饰器。装饰器(decorator)用于修改函数或类的行为。实现这一点的方法是定义一个返回另一个函数的函数(装饰器)。这听起来很复杂,但是通过这个例子你会理解所有的东西:

def logging_decorator(func):
 def logging_wrapper(*args, **kwargs):
 print(f'Before {func.__name__}')
 func(*args, **kwargs)
 print(f'After {func.__name__}')
 return logging_wrapper
 
@logging_decorator
def sum(x, y):
 print(x + y)
 
sum(2, 5)
> Before sum
> 7
> After sum

让我们一步一步来:

  1. 首先,我们在第1行定义logging_decorator函数。它只接受一个参数,也就是我们要修饰的函数。
  2. 在内部,我们定义了另一个函数:logging_wrapper。然后返回logging_wrapper,并使用它来代替原来的修饰函数。
  3. 在第7行,您可以看到如何将装饰器应用到sum函数。
  4. 在第11行,当我们调用sum时,它不仅仅调用sum。它将调用logging_wrapper,它将在调用sum之前和之后记录日志。

2.为什么需要装饰器

这很简单:可读性。Python因其清晰简洁的语法而备受赞誉,装饰器也不例外。如果有任何行为是多个函数共有的,那么您可能需要制作一个装饰器。下面是一些可能会派上用场的例子:

  • 在运行时检查实参类型
  • 基准函数调用
  • 缓存功能的结果
  • 计数函数调用
  • 检查元数据(权限、角色等)
  • 元编程

和更多…

现在我们将列出一些代码示例。

3.例子

带有返回值的装饰器

假设我们想知道每个函数调用需要多长时间。而且,函数大多数时候都会返回一些东西,所以装饰器也必须处理它:

def timer_decorator(func):
 def timer_wrapper(*args, **kwargs):
 import datetime  
 before = datetime.datetime.now()  
 result = func(*args,**kwargs) 
 after = datetime.datetime.now()  
 print "Elapsed Time = {0}".format(after-before) 
 return result
 
@timer_decorator
def sum(x, y):
 print(x + y)
 return x + y
 
sum(2, 5)
> 7
> Elapsed Time = some time

可以看到,我们将返回值存储在第5行的result中。但在返回之前,我们必须完成对函数的计时。这是一个没有装饰者就不可能实现的行为例子。

带有参数的装饰器

有时候,我们想要一个接受值的装饰器(比如Flask中的@app.route('/login'):

def permission_decorator(permission):
 def _permission_decorator(func):
 def permission_wrapper(*args, **kwargs):
 if someUserApi.hasPermission(permission):
 result = func(*args, **kwargs)
 return result
 return None
 return permission wrapper
 return _permission_decorator

@permission_decorator('admin')
def delete_user(user):
 someUserApi.deleteUser(user)

为了实现这一点,我们定义了一个额外的函数,它接受一个参数并返回一个装饰器。

带有类的装饰器

使用类代替函数来修饰是可能的。唯一的区别是语法,所以请使用您更熟悉的语法。下面是使用类重写的日志装饰器:

class Logging: 
 
 def __init__(self, function): 
 self.function = function 
 
 def __call__(self, *args, **kwargs):
 print(f'Before {self.function.__name__}')
 self.function(*args, **kwargs)
 print(f'After {self.function.__name__}')
 
 
@Logging
def sum(x, y):
 print(x + y)

sum(5, 2)
> Before sum
> 7
> After sum

这样做的好处是,您不必处理嵌套函数。你所需要做的就是定义一个类并覆盖__call__方法。

装饰类

有时,您可能想要修饰类中的每个方法。你可以这样写

class MyClass: 
 @decorator 
 def func1(self): 
 pass 
 @decorator 
 def func2(self): 
 pass

但如果你有很多方法,这可能会失控。值得庆幸的是,有一种方法可以一次性装饰整个班级:

def logging_decorator(func):
 def logging_wrapper(*args, **kwargs):
 print(f'Before {func.__name__}')
 result = func(*args, **kwargs)
 print(f'After {func.__name__}')
 return result
 return logging_wrapper

def log_all_class_methods(cls):
 class NewCls(object):
 def __init__(self, *args, **kwargs):
 self.original = cls(*args, **kwargs)
 
 def __getattribute__(self, s):
 try: 
 x = super(NewCls,self).__getattribute__(s)
 except AttributeError: 
 pass
 else:
 return x
 x = self.original.__getattribute__(s)
 if type(x) == type(self.__init__): 
 return logging_decorator(x)  
 else:
 return x
 return NewCls
 
@log_all_class_methods
class SomeMethods:
 def func1(self):
 print('func1')
 
 def func2(self):
 print('func2')
 
methods = SomeMethods()
methods.func1()
> Before func1
> func1
> After func1

现在,不要惊慌。这看起来很复杂,但逻辑是一样的:

  • 首先,我们让logging_decorator保持原样。它将应用于类的所有方法。
  • 然后我们定义一个新的装饰器:log_all_class_methods。它类似于普通的装饰器,但却返回一个类。
  • NewCls有一个自定义的__getattribute__。对于对原始类的所有调用,它将使用logging_decorator装饰函数。

内置的修饰符

您不仅可以定义自己的decorator,而且在标准库中也提供了一些decorator。我将列出与我一起工作最多的三个人:

@property -一个内置插件的装饰器,它允许你为类属性定义getter和setter。

@lru_cache - functools模块的装饰器。它记忆函数参数和返回值,这对于纯函数(如阶乘)很方便。

@abstractmethod——abc模块的装饰器。指示该方法是抽象的,且缺少实现细节。

以上就是python 装饰器重要在哪的详细内容,更多关于python 装饰器的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python实现绘制树枝简单示例
Jul 24 Python
跟老齐学Python之永远强大的函数
Sep 14 Python
利用python爬取斗鱼app中照片方法实例
Dec 03 Python
用python实现对比两张图片的不同
Feb 05 Python
Python 3.7新功能之dataclass装饰器详解
Apr 21 Python
利用Python实现在同一网络中的本地文件共享方法
Jun 04 Python
djang常用查询SQL语句的使用代码
Feb 15 Python
Django如何实现网站注册用户邮箱验证功能
Aug 14 Python
Python随机函数库random的使用方法详解
Aug 21 Python
python实现密度聚类(模板代码+sklearn代码)
Apr 27 Python
python操作链表的示例代码
Sep 27 Python
K近邻法(KNN)相关知识总结以及如何用python实现
Jan 28 Python
python爬虫如何解决图片验证码
Feb 14 #Python
Python实现粒子群算法的示例
Feb 14 #Python
Python中对象的比较操作==和is区别详析
Feb 12 #Python
python绘图模块之利用turtle画图
Feb 12 #Python
Python列表的深复制和浅复制示例详解
Feb 12 #Python
Python就将所有的英文单词首字母变成大写
Feb 12 #Python
详解Java中一维、二维数组在内存中的结构
Feb 11 #Python
You might like
php 文件上传实例代码
2012/04/19 PHP
SESSION信息保存在哪个文件目录下以及能够用来保存什么类型的数据
2012/06/17 PHP
Zend Framework开发入门经典教程
2016/03/23 PHP
Yii框架实现多数据库配置和操作的方法
2017/05/25 PHP
PHP+RabbitMQ实现消息队列的完整代码
2019/03/20 PHP
PhpStorm+xdebug+postman调试技巧分享
2020/09/15 PHP
AJAX的跨域与JSONP(为文章自动添加短址的功能)
2010/01/17 Javascript
jQuery如何取id有.的值一般的方法是取不到的
2014/04/18 Javascript
JSON格式的键盘编码对照表
2015/01/29 Javascript
node.js集成百度UE编辑器
2015/02/05 Javascript
javascript实现简单查找与替换的方法
2015/07/22 Javascript
js实现改进的仿蓝色论坛导航菜单效果代码
2015/09/06 Javascript
探究Javascript模板引擎mustache.js使用方法
2016/01/26 Javascript
vueJS简单的点击显示与隐藏的效果【实现代码】
2016/05/03 Javascript
JavaScript 基础函数_深入剖析变量和作用域
2016/05/18 Javascript
AngularJS实现自定义指令与控制器数据交互的方法示例
2017/06/19 Javascript
vue.js中toast用法及使用toast弹框的实例代码
2018/08/27 Javascript
微信小程序API—获取定位的详解
2019/04/30 Javascript
JS箭头函数和常规函数之间的区别实例分析【 5 个区别】
2020/05/27 Javascript
[08:42]DOTA2每周TOP10 精彩击杀集锦vol.2
2014/06/25 DOTA
[09:31]2016国际邀请赛中国区预选赛Yao赛后采访 答题送礼
2016/06/27 DOTA
[34:39]Secret vs VG 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
python执行外部程序的常用方法小结
2015/03/21 Python
初步解析Python中的yield函数的用法
2015/04/03 Python
Python数据可视化编程通过Matplotlib创建散点图代码示例
2017/12/09 Python
在python中获取div的文本内容并和想定结果进行对比详解
2019/01/02 Python
Pytorch高阶OP操作where,gather原理
2020/04/30 Python
跨域修改iframe页面内容详解
2019/10/31 HTML / CSS
Charles & Colvard官网:美国莫桑石品牌
2019/06/05 全球购物
新领导上任欢迎词
2014/01/13 职场文书
公司投资建议书
2014/05/16 职场文书
党的生日活动方案
2014/08/15 职场文书
2015年党员自评材料
2014/12/17 职场文书
保留意见审计报告
2015/06/05 职场文书
幼儿园小班班务总结
2015/08/03 职场文书
总结Python常用的魔法方法
2021/05/25 Python