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的Django框架部署的一些建议
Apr 09 Python
Python通过90行代码搭建一个音乐搜索工具
Jul 29 Python
Python三级菜单的实例
Sep 13 Python
神经网络python源码分享
Dec 15 Python
Python爬虫——爬取豆瓣电影Top250代码实例
Apr 17 Python
Python中的引用知识点总结
May 20 Python
pandas DataFrame索引行列的实现
Jun 04 Python
使用python制作一个为hex文件增加版本号的脚本实例
Jun 12 Python
Python简易版停车管理系统
Aug 12 Python
详解Django-channels 实现WebSocket实例
Aug 22 Python
Python绘图之柱形图绘制详解
Jul 28 Python
Jupyter Notebook 安装配置与使用详解
Jan 06 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生成EXCEL的东东
2006/10/09 PHP
GBK的页面输出JSON格式的php函数
2010/02/16 PHP
php实现比较全的数据库操作类
2015/06/18 PHP
PHPstorm快捷键(分享)
2017/07/17 PHP
mysql输出数据赋给js变量报unterminated string literal错误原因
2010/05/22 Javascript
js关闭当前页面(窗口)的几种方式总结
2013/03/05 Javascript
javascript实现rgb颜色转换成16进制格式
2015/07/10 Javascript
Sequelize中用group by进行分组聚合查询
2016/12/12 Javascript
Angularjs 实现动态添加控件功能
2017/05/25 Javascript
自定义PC微信扫码登录样式写法
2017/12/12 Javascript
如何去除vue项目中的#及其ie9兼容性
2018/01/11 Javascript
Angularjs中date过滤器失效的问题及解决方法
2018/07/06 Javascript
react native 文字轮播的实现示例
2018/07/27 Javascript
vue interceptor 使用教程实例详解
2018/09/13 Javascript
小程序中英文混合排序问题解决
2019/08/02 Javascript
详解vue-router 动态路由下子页面多页共活的解决方案
2019/12/22 Javascript
JS前端广告拦截实现原理解析
2020/02/17 Javascript
js实现百度登录窗口拖拽效果
2020/03/19 Javascript
解决qrcode.js生成二维码时必须定义一个空div的问题
2020/07/09 Javascript
python实现线程池的方法
2015/06/30 Python
浅析Python中的for 循环
2016/06/09 Python
Python基础中所出现的异常报错总结
2016/11/19 Python
python 文件转成16进制数组的实例
2018/07/09 Python
django框架自定义用户表操作示例
2018/08/07 Python
python3转换code128条形码的方法
2019/04/17 Python
利用Python查看微信共同好友功能的实现代码
2019/04/24 Python
Python线程障碍对象Barrier原理详解
2019/12/02 Python
如何在scrapy中集成selenium爬取网页的方法
2020/11/18 Python
乌克兰香水和化妆品网站:Notino.ua
2018/03/26 全球购物
单位办理社保介绍信
2014/01/10 职场文书
工作表现评语
2014/01/19 职场文书
保护环境倡议书范文
2014/05/13 职场文书
安全生产目标管理责任书
2014/07/25 职场文书
2014国庆节商场促销活动策划方案
2014/09/16 职场文书
告别网页搜索!教你用python实现一款属于自己的翻译词典软件
2021/06/03 Python
Java spring单点登录系统
2021/09/04 Java/Android