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使用scrapy解析js示例
Jan 23 Python
Python实现在matplotlib中两个坐标轴之间画一条直线光标的方法
May 20 Python
将Python的Django框架与认证系统整合的方法
Jul 24 Python
Python 生成 -1~1 之间的随机数矩阵方法
Aug 04 Python
利用python循环创建多个文件的方法
Oct 25 Python
Python自动发送邮件的方法实例总结
Dec 08 Python
Python使用pyserial进行串口通信的实例
Jul 02 Python
python格式化输出保留2位小数的实现方法
Jul 02 Python
Django处理Ajax发送的Get请求代码详解
Jul 29 Python
vscode 配置 python3开发环境的方法
Sep 19 Python
如何解决cmd运行python提示不是内部命令
Jul 01 Python
pycharm 配置svn的图文教程(手把手教你)
Jan 15 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
Thinkphp和onethink实现微信支付插件
2016/04/13 PHP
php 中奖概率算法实现代码
2017/01/25 PHP
PHP实现在数据库百万条数据中随机获取20条记录的方法
2017/04/19 PHP
PHP 应用容器化以及部署方法
2018/02/12 PHP
laravel框架实现去掉URL中index.php的方法
2019/10/12 PHP
初学prototype,发个JS接受URL参数的代码
2006/09/25 Javascript
jquery中eq和get的区别与使用方法
2011/04/14 Javascript
nodejs的require模块(文件模块/核心模块)及路径介绍
2013/01/14 NodeJs
创建、调用JavaScript对象的方法集锦
2014/12/24 Javascript
JavaScript实现的双向跨域插件分享
2015/01/31 Javascript
浅谈JavaScript中运算符的优先级
2015/07/07 Javascript
浅谈在js传递参数中含加号(+)的处理方式
2016/10/11 Javascript
[原创]JavaScript语法高亮插件highlight.js用法详解【附highlight.js本站下载】
2016/11/01 Javascript
JS ES6多行字符串与连接字符串的表示方法
2017/04/26 Javascript
自适应布局meta标签中viewport、content、width、initial-scale、minimum-scale、maximum-scale总结
2017/08/18 Javascript
基于jQuery的$.getScript方法去加载javaScript文档解析
2017/11/08 jQuery
JavaScript中变量、指针和引用功能与操作示例
2018/08/04 Javascript
JavaScript从原型到原型链深入理解
2019/06/03 Javascript
jQuery实现全选、反选和不选功能的方法详解
2019/12/04 jQuery
jquery实现手风琴案例
2020/05/04 jQuery
微信小程序调用wx.getImageInfo遇到的坑解决
2020/05/31 Javascript
js实现简单的无缝轮播效果
2020/09/05 Javascript
跟老齐学Python之让人欢喜让人忧的迭代
2014/10/02 Python
Python2中的raw_input() 与 input()
2015/06/12 Python
python2与python3爬虫中get与post对比解析
2019/09/18 Python
Python requests及aiohttp速度对比代码实例
2020/07/16 Python
麦德龙官方海外旗舰店:德国麦德龙超市
2017/12/23 全球购物
意大利在线大学图书馆:Libreria universitaria
2019/07/16 全球购物
美国户外服装和装备购物网站:Outland USA
2020/03/22 全球购物
如何设定的weblogic的热启动模式(开发模式)与产品发布模式
2012/09/08 面试题
个人思想理论学习的自我鉴定
2013/11/30 职场文书
个人求职简历中英文自我评价
2013/12/16 职场文书
党员创先争优公开承诺书
2014/03/28 职场文书
讲解员培训方案
2014/05/04 职场文书
2015年校医个人工作总结
2015/07/24 职场文书
javaScript Array api梳理
2021/03/31 Javascript