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的简单爬虫代码
May 26 Python
Python Deque 模块使用详解
Jul 04 Python
在Python中关于中文编码问题的处理建议
Apr 08 Python
用python实现简单EXCEL数据统计的实例
Jan 24 Python
Python中str.format()详解
Mar 12 Python
Python实现破解猜数游戏算法示例
Sep 25 Python
Django 生成登陆验证码代码分享
Dec 12 Python
Python实现二维数组输出为图片
Apr 03 Python
Python交互环境下实现输入代码
Jun 22 Python
pytorch方法测试——激活函数(ReLU)详解
Jan 15 Python
TensorFlow:将ckpt文件固化成pb文件教程
Feb 11 Python
Python-jenkins模块之folder相关操作介绍
May 12 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 include_path设置技巧分享
2011/07/03 PHP
微信公众平台网页授权获取用户基本信息中授权回调域名设置的变动
2014/10/21 PHP
如何让CI框架支持service层
2014/10/29 PHP
php使用pdo连接sqlite3的配置示例
2016/05/27 PHP
php导出csv文件,可导出前导0实例代码
2016/11/16 PHP
thinkphp分页集成实例
2017/07/24 PHP
js 表格隔行颜色
2009/12/02 Javascript
用函数模板,写一个简单高效的 JSON 查询器的方法介绍
2013/04/17 Javascript
JS实现当前页居中分页效果的方法
2015/06/18 Javascript
理解javascript定时器中的setTimeout与setInterval
2016/02/23 Javascript
深入理解JS正则表达式---分组
2016/07/18 Javascript
Node.js包管理器Yarn的入门介绍与安装
2016/10/17 Javascript
jQuery 插件实现随机自由弹跳气泡样式
2017/01/12 Javascript
Koa 中的错误处理解析
2019/04/09 Javascript
微信小程序自定义组件实现环形进度条
2020/11/17 Javascript
vue + typescript + video.js实现 流媒体播放 视频监控功能
2019/07/07 Javascript
详解Vue 换肤方案验证
2019/08/28 Javascript
微信小程序实现锚点功能
2019/11/20 Javascript
js+canvas绘制图形验证码
2020/09/21 Javascript
vue-cli中实现响应式布局的方法
2021/03/02 Vue.js
探寻python多线程ctrl+c退出问题解决方案
2014/10/23 Python
Python中urllib2模块的8个使用细节分享
2015/01/01 Python
Python栈类实例分析
2015/06/15 Python
Python入门_浅谈for循环、while循环
2017/05/16 Python
Python人脸识别第三方库face_recognition接口说明文档
2019/05/03 Python
给你一面国旗 教你用python画中国国旗
2019/09/24 Python
世界最大的私人旅行指南出版商:孤独星球
2016/08/23 全球购物
Expedia法国:全球最大在线旅游公司
2018/09/30 全球购物
介绍下Java的输入输出流
2014/01/22 面试题
一些高难度的SQL面试题
2016/11/29 面试题
《每逢佳节倍思亲》教后反思
2014/04/19 职场文书
党员群众路线整改措施及今后努力方向
2014/10/28 职场文书
精神文明建设汇报材料
2014/12/24 职场文书
智慧人生:永远不需要向任何人解释你自己
2019/08/20 职场文书
MySQL系列之六 用户与授权
2021/07/02 MySQL
SQL语句中EXISTS的详细用法大全
2022/06/25 MySQL