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遍历目录的4种方法实例介绍
Apr 13 Python
python使用urllib2实现发送带cookie的请求
Apr 28 Python
python字符串的常用操作方法小结
May 21 Python
举例讲解Python中字典的合并值相加与异或对比
Jun 04 Python
5个很好的Python面试题问题答案及分析
Jan 19 Python
TensorFlow saver指定变量的存取
Mar 10 Python
pycharm: 恢复(reset) 误删文件的方法
Oct 22 Python
Python3日期与时间戳转换的几种方法详解
Jun 04 Python
python傅里叶变换FFT绘制频谱图
Jul 19 Python
简单了解pytest测试框架setup和tearDown
Apr 14 Python
python3中for循环踩过的坑记录
Dec 14 Python
编写python程序的90条建议
Apr 14 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
Win9x/ME下Apache+PHP安装配置
2006/10/09 PHP
与数据库连接
2006/10/09 PHP
PHP中imagick函数的中文解释
2015/01/21 PHP
innerhtml用法 innertext用法 以及innerHTML与innertext的区别
2009/10/26 Javascript
JQuery Tips(4) 一些关于提高JQuery性能的Tips
2009/12/19 Javascript
javascript+iframe 实现无刷新载入整页的代码
2010/03/17 Javascript
javascript setTimeout和setInterval计时的区别详解
2013/06/21 Javascript
将form表单中的元素转换成对象的方法适用表单提交
2014/05/02 Javascript
jQuery中$.click()无效问题分析
2015/01/29 Javascript
js+cookies实现悬浮购物车的方法
2015/05/25 Javascript
实现隔行换色效果的两种方式【实用】
2016/11/27 Javascript
Vue实例简单方法介绍
2017/01/20 Javascript
微信提示 在浏览器打开 效果实现过程解析
2019/09/10 Javascript
vue移动端下拉刷新和上滑加载
2020/10/27 Javascript
使用Mixin设计模式进行Python编程的方法讲解
2016/06/21 Python
python简单实现AES加密和解密
2019/03/28 Python
详解python中的线程与线程池
2019/05/10 Python
Django models文件模型变更错误解决
2020/05/11 Python
Python中的全局变量如何理解
2020/06/04 Python
Python爬虫入门教程01之爬取豆瓣Top电影
2021/01/24 Python
Sql面试题
2013/03/20 面试题
在子网210.27.48.21/30种有多少个可用地址?分别是什么?
2014/07/27 面试题
大三自我鉴定范文
2013/10/05 职场文书
《夸父追日》教学反思
2014/02/26 职场文书
2014年圣诞节促销方案
2014/03/14 职场文书
班子个人四风问题整改措施
2014/10/04 职场文书
事业单位年度考核评语
2014/12/31 职场文书
欢迎词怎么写
2015/01/23 职场文书
客户经理岗位职责
2015/01/31 职场文书
后勤工作个人总结
2015/02/28 职场文书
三国演义读书笔记
2015/06/25 职场文书
八年级作文之感悟亲情
2019/11/20 职场文书
Java基于字符界面的简易收银台
2021/06/26 Java/Android
python利用pandas分析学生期末成绩实例代码
2021/07/09 Python
基于PyQt5制作一个群发邮件工具
2022/04/08 Python
阿里云k8s服务升级时502错误 springboot项目应用
2022/04/09 Servers