Python 装饰器原理、定义与用法详解


Posted in Python onDecember 07, 2019

本文实例讲述了Python 装饰器原理、定义与用法。分享给大家供大家参考,具体如下:

Python 装饰器

一、何为装饰器

1、在函数中定义函数

在函数中定义另外的函数,就是说可以创建嵌套的函数,例子如下

def sayHi(name="hjj2"):
 print 'inside sayHi() func'
 def greet():
  return 'inside greet() func'
 print(greet())
sayHi()
#output
#  inside sayHi() func
#  inside greet() func

2、将函数作为参数传给另外一个函数,装饰器原型

def sayHi():
 return 'hi hjj2'
def doSthBeforeSayHi(func):
 print 'before sayHi func'
 print(func())
doSthBeforeSayHi(sayHi)
#output
#  before sayHi func
#  hi hjj2

3、实现一个装饰器

在第二步中,我们已经基本探究到装饰器的原理了,python装饰器做的事就是通过封装一个函数并且用这样或那样的方式来修改它的行为。不带@的初步示例如下:

def new_decorator(func):
  def wrapDecorator():
   print 'before func'
   func()
   print 'after func'
  return wrapDecorator
def func_require_decorator():
  print 'a func need decorator'
func_require_decorator()
#ouput: a func need decorator
func_require_decorator = new_decorator(func_require_decorator)
func_require_decorator()
#ouput:
#  before func
#  a func need decorator
#  after func

使用@来运行装饰器

@new_decorator
func_require_decorator()
#ouput:
#  before func
#  a func need decorator
#  after func

这里我们可以看到,这两个例子的运行结果是一样的。所以我们能想象得到@new_decorator的作用就是

func_require_decorator = new_decorator(func_require_decorator)

我们继续优化这个装饰器,现在我们有一个问题就是,如果我们想要通过print(func_require_decorator.__name__)就会报错# Output: wrapTheFunction。这样就需要借助python提供的functools.wraps来解决了

@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

from functools import wraps
def new_decorator(func):
  @wraps(func)
  def wrapDecorator():
   print 'before func'
   func()
   print 'after func'
  return wrapDecorator
def func_require_decorator():
  print 'a func need decorator'
@new_decorator
func_require_decorator()
print(func_require_decorator.__name__)
#ouput: func_require_decorator

二、使用场景

1、授权,大体例子

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

2、日志:

from functools import wraps
def logit(logfile='out.log'):
  def logging_decorator(func):
    @wraps(func)
    def wrapped_function(*args,**kwargs):
      log_string = func.__name__+"was called"
      print(log_string)
      with open(logfile,'a') as opened_file:
        opened_file.write(log_string+'\n')
      return func(*args,**kwargs)
    return wrapped_function
  return logging_decorator
@logit()
def func1():
  pass
func1()

3、其他如flask中的@app.route()

三、装饰器类

1、将上面的日志装饰器变为类的初步模型如下

from functools import wraps
class logit(object):
  def __init__(self, logfile='out.log'):
    self.logfile = logfile
  def __call__(self, func):
    @wraps(func)
    def wrapped_function(*args, **kwargs):
      log_string = func.__name__ + "was called"
      print(log_string)
      # 打开logfile并写入
      with open(self.logfile, 'a') as open_file:
        # 将日志写到指定文件
        open_file.write(log_string + '\n')
      # 发送一个通知
      self.notify()
      return func(*args, **kwargs)
    return wrapped_function
  def notify(self):
    pass
@logit()
def myfunc1():
  pass
class email_logit(logit):
  '''
  实现在函数调用时发送email
  '''
  def __init__(self, email='admin@xxx.com', *args, **kwargs):
    self.email = email
    super(email_logit, self).__init__(*args, **kwargs)
  def notify(self):
    '''
    发送邮件通知
    '''
    pass

通过这种方式,我们可以定义我们在自己的需求,减少代码的冗余,提高复用率。

至此,关于装饰器的探索就结束啦。

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python3 能振兴 Python的原因分析
Nov 28 Python
python 输出上个月的月末日期实例
Apr 11 Python
转换科学计数法的数值字符串为decimal类型的方法
Jul 16 Python
详解基于django实现的webssh简单例子
Jul 17 Python
python配置grpc环境
Jan 01 Python
python flask解析json数据不完整的解决方法
May 26 Python
用sqlalchemy构建Django连接池的实例
Aug 29 Python
pytorch 获取tensor维度信息示例
Jan 03 Python
Python实现计算图像RGB均值方式
Jun 04 Python
Python调用C/C++的方法解析
Aug 05 Python
Python爬虫分析微博热搜关键词的实现代码
Feb 22 Python
Python创建SQL数据库流程逐步讲解
Sep 23 Python
Python Pandas 转换unix时间戳方式
Dec 07 #Python
Pandas-Cookbook 时间戳处理方式
Dec 07 #Python
Python数据可视化:饼状图的实例讲解
Dec 07 #Python
Python数据可视化:幂律分布实例详解
Dec 07 #Python
Python数据可视化:泊松分布详解
Dec 07 #Python
python-numpy-指数分布实例详解
Dec 07 #Python
Python Sympy计算梯度、散度和旋度的实例
Dec 06 #Python
You might like
咖啡豆分级制度 咖啡豆等级分类 咖啡豆是按口感分类的吗?
2021/03/05 新手入门
PHP写MySQL数据 实现代码
2009/06/15 PHP
php foreach、while性能比较
2009/10/15 PHP
用来解析.htgroup文件的PHP类
2012/09/05 PHP
支付宝服务窗API接口开发php版本
2016/07/20 PHP
浅谈htmlentities 、htmlspecialchars、addslashes的使用方法
2016/12/09 PHP
ThinkPHP实现静态缓存和动态缓存示例代码
2017/05/02 PHP
不要使用jQuery触发原生事件的方法
2014/03/03 Javascript
javascript实现在线客服效果
2015/07/15 Javascript
vue页面使用阿里oss上传功能的实例(二)
2017/08/09 Javascript
JavaScript自执行函数和jQuery扩展方法详解
2017/10/27 jQuery
Vue添加请求拦截器及vue-resource 拦截器使用
2017/11/23 Javascript
通过函数作用域和块级作用域看javascript的作用域链
2018/08/05 Javascript
Nuxt升级2.0.0时出现的问题(小结)
2018/10/08 Javascript
详解在create-react-app使用less与antd按需加载
2018/12/06 Javascript
Vue.js特性Scoped Slots的浅析
2019/02/20 Javascript
vue+导航锚点联动-滚动监听和点击平滑滚动跳转实例
2019/11/13 Javascript
js实现圆形显示鼠标单击位置
2020/02/11 Javascript
关于vue-cli3打包代码后白屏的解决方案
2020/09/02 Javascript
在antd4.0中Form使用initialValue操作
2020/11/02 Javascript
使用python调用浏览器并打开一个网址的例子
2014/06/05 Python
Django1.7+python 2.78+pycharm配置mysql数据库
2016/10/09 Python
python字典多键值及重复键值的使用方法(详解)
2016/10/31 Python
在Python中使用AOP实现Redis缓存示例
2017/07/11 Python
python flask框架实现传数据到js的方法分析
2019/06/11 Python
Python通用函数实现数组计算的方法
2019/06/13 Python
Python解压 rar、zip、tar文件的方法
2019/11/19 Python
pyautogui自动化控制鼠标和键盘操作的步骤
2020/04/01 Python
python opencv实现图片缺陷检测(讲解直方图以及相关系数对比法)
2020/04/07 Python
C#中有没有运算符重载?能否使用指针?
2014/05/05 面试题
医院办公室主任职责
2013/12/29 职场文书
领导干部培训感言
2014/01/23 职场文书
法律专业求职信
2014/05/24 职场文书
学生个人总结范文
2015/02/15 职场文书
毕业生捐书活动倡议书
2015/04/27 职场文书
2019年销售部季度工作计划3篇
2019/10/09 职场文书