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 相关文章推荐
Python isinstance函数介绍
Apr 14 Python
python计算文本文件行数的方法
Jul 06 Python
python实现中文转换url编码的方法
Jun 14 Python
python3 与python2 异常处理的区别与联系
Jun 19 Python
Django基础之Model操作步骤(介绍)
May 27 Python
基于python实现在excel中读取与生成随机数写入excel中
Jan 04 Python
每天迁移MySQL历史数据到历史库Python脚本
Apr 13 Python
python中找出numpy array数组的最值及其索引方法
Apr 17 Python
详解Python3迁移接口变化采坑记
Oct 11 Python
Keras Convolution1D与Convolution2D区别说明
May 22 Python
Python获取指定网段正在使用的IP
Dec 14 Python
Python WSGI 规范简介
Apr 11 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
php统计文件大小,以GB、MB、KB、B输出
2011/05/29 PHP
zend framework文件上传功能实例代码
2013/12/25 PHP
php使用多个进程同时控制文件读写示例
2014/02/28 PHP
phpStorm+XDebug+chrome 配置详解
2019/04/01 PHP
Laravel5.4框架中视图共享数据的方法详解
2019/09/05 PHP
在laravel框架中实现封装公共方法全局调用
2019/10/14 PHP
推荐dojo学习笔记
2007/03/24 Javascript
JavaScript 学习笔记(十六) js事件
2010/02/01 Javascript
JS 屏蔽键盘不可用与鼠标右键不可用的方法
2013/11/18 Javascript
JavaScript字符串对象toUpperCase方法入门实例(用于把字母转换为大写)
2014/10/17 Javascript
node.js中的http.request方法使用说明
2014/12/14 Javascript
node.js中的fs.fchmod方法使用说明
2014/12/16 Javascript
JS动态修改表格cellPadding和cellSpacing的方法
2015/03/31 Javascript
基于jquery实现即时检查格式是否正确的表单
2016/05/06 Javascript
微信小程序 省市区选择器实例详解(附源码下载)
2017/01/05 Javascript
JavaScript 中 apply 、call 的详解
2017/03/21 Javascript
微信小程序的mpvue框架快速上手指南
2019/05/15 Javascript
vue实现标签云效果的方法详解
2019/08/28 Javascript
JS实现简单日历特效
2020/01/03 Javascript
Vue中函数防抖节流的理解及应用实现
2020/04/24 Javascript
nuxt静态部署打包相对路径操作
2020/11/06 Javascript
scrapy爬虫实例分享
2017/12/28 Python
用Python从0开始实现一个中文拼音输入法的思路详解
2019/07/20 Python
Python如何使用argparse模块处理命令行参数
2019/12/11 Python
Tensorflow 使用pb文件保存(恢复)模型计算图和参数实例详解
2020/02/11 Python
利用Python裁切tiff图像且读取tiff,shp文件的实例
2020/03/10 Python
对python中return与yield的区别详解
2020/03/12 Python
Pytorch如何切换 cpu和gpu的使用详解
2021/03/01 Python
俄罗斯花园种植材料批发和零售网上商店:Беккер
2019/07/22 全球购物
财务方面个人工作的自我评价
2013/12/28 职场文书
通信工程专业求职信
2014/06/04 职场文书
2014年煤矿工人工作总结
2014/12/08 职场文书
饭店服务员岗位职责
2015/02/09 职场文书
初中生思想道德自我评价
2015/03/09 职场文书
创业计划书之美甲店
2019/09/20 职场文书
MySQL的意向共享锁、意向排它锁和死锁
2022/07/15 MySQL