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 struct.unpack
Sep 06 Python
python实现人人网登录示例分享
Jan 19 Python
总结用Pdb库调试Python的方式及常用的命令
Aug 18 Python
Python3学习笔记之列表方法示例详解
Oct 06 Python
Python OpenCV利用笔记本摄像头实现人脸检测
Aug 20 Python
Python button选取本地图片并显示的实例
Jun 13 Python
python提取xml里面的链接源码详解
Oct 15 Python
Python新手学习raise用法
Jun 03 Python
python框架flask入门之路由及简单实现方法
Jun 07 Python
Python实现迪杰斯特拉算法过程解析
Sep 18 Python
python从PDF中提取数据的示例
Oct 30 Python
python实现简单倒计时功能
Apr 21 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
PHILIPS D1835/D1875的电路分析与打理
2021/03/02 无线电
php面向对象全攻略 (九)访问类型
2009/09/30 PHP
在PHP中实现Javascript的escape()函数代码
2010/08/08 PHP
详细对比php中类继承和接口继承
2018/10/11 PHP
PHP7 其他修改
2021/03/09 PHP
JavaScript国旗变换效果代码
2008/08/13 Javascript
JavaScript 检测浏览器和操作系统的脚本
2008/12/26 Javascript
js中巧用cssText属性批量操作样式
2011/03/13 Javascript
JavaScript地图拖动功能SpryMap的简单实现
2013/07/17 Javascript
jquery 漂亮的删除确认和提交无刷新删除示例
2013/11/13 Javascript
使用百度地图api实现根据地址查询经纬度
2014/12/11 Javascript
node.js中的fs.futimes方法使用说明
2014/12/17 Javascript
Javascript数组操作函数总结
2015/02/05 Javascript
js给selected添加options的方法
2015/05/06 Javascript
AngularJS中监视Scope变量以及外部调用Scope方法
2016/01/23 Javascript
JavaScript学习笔记整理_简单实现枚举类型,扑克牌应用
2016/09/19 Javascript
使用yeoman构建angular应用的方法
2017/08/14 Javascript
浅谈Vuejs中nextTick()异步更新队列源码解析
2017/12/31 Javascript
微信小程序 JS动态修改样式的实现方法
2018/12/16 Javascript
node Buffer缓存区常见操作示例
2019/05/04 Javascript
JavaScript实现的滚动公告特效【基于jQuery】
2019/07/10 jQuery
Python编程中的反模式实例分析
2014/12/08 Python
Python实现获取命令行输出结果的方法
2017/06/10 Python
Python DataFrame 设置输出不显示index(索引)值的方法
2018/06/07 Python
Python动态生成多维数组的方法示例
2018/08/09 Python
浅谈Python2之汉字编码为unicode的问题(即类似\xc3\xa4)
2019/08/12 Python
tensorflow指定GPU与动态分配GPU memory设置
2020/02/03 Python
python同时遍历两个list用法说明
2020/05/02 Python
Python Tricks 使用 pywinrm 远程控制 Windows 主机的方法
2020/07/21 Python
Omio中国:全欧洲低价大巴、火车和航班搜索和比价
2018/08/09 全球购物
杭州-飞时达软件有限公司.net笔面试
2012/04/28 面试题
大学应届生的自我评价
2014/03/06 职场文书
《池塘边的叫声》教学反思
2014/04/12 职场文书
心理健康日活动总结
2014/05/08 职场文书
群众路线个人剖析材料及整改措施
2014/11/04 职场文书
师范生见习总结范文
2015/06/23 职场文书