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 datetime时间格式化去掉前导0
Jul 31 Python
python开发之字符串string操作方法实例详解
Nov 12 Python
python实现字典(dict)和字符串(string)的相互转换方法
Mar 01 Python
python3实现磁盘空间监控
Jun 21 Python
详解用Python练习画个美队盾牌
Mar 23 Python
基于Python获取照片的GPS位置信息
Jan 20 Python
Python3 读取Word文件方式
Feb 13 Python
python:批量统计xml中各类目标的数量案例
Mar 10 Python
Python SMTP配置参数并发送邮件
Jun 16 Python
使用PyWeChatSpy自动回复微信拍一拍功能的实现代码
Jul 02 Python
Pandas中两个dataframe的交集和差集的示例代码
Dec 13 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
php使用GeoIP库实例
2014/06/27 PHP
php图片水印添加、压缩、剪切的封装类实现
2020/04/18 PHP
解决安装WampServer时提示缺少msvcr110.dll文件的问题
2017/07/09 PHP
关于Yii中模型场景的一些简单介绍
2019/09/22 PHP
JQuery的ajax基础上的超强GridView展示
2009/09/18 Javascript
Chrome中模态对话框showModalDialog返回值问题的解决方法
2010/05/25 Javascript
jquery快捷动态绑定键盘事件的操作函数代码
2013/10/17 Javascript
自己动手写的javascript前端等待控件
2015/10/30 Javascript
BootStrap的两种模态框方式
2017/05/10 Javascript
原生js实现trigger方法示例代码
2019/05/22 Javascript
vue 解决computed修改data数据的问题
2019/11/06 Javascript
三剑客:offset、client和scroll还傻傻分不清?
2020/12/04 Javascript
[48:53]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS VG第一场
2014/05/26 DOTA
[46:16]2018DOTA2亚洲邀请赛3月30日 小组赛B组 iG VS VP
2018/03/31 DOTA
[01:20:05]DOTA2-DPC中国联赛 正赛 Ehome vs VG BO3 第二场 2月5日
2021/03/11 DOTA
Python时区设置方法与pytz查询时区教程
2013/11/27 Python
python中mechanize库的简单使用示例
2014/01/10 Python
python构造icmp echo请求和实现网络探测器功能代码分享
2014/01/10 Python
在Python中操作时间之tzset()方法的使用教程
2015/05/22 Python
浅谈function(函数)中的动态参数
2017/04/30 Python
Python使用zip合并相邻列表项的方法示例
2018/03/17 Python
django框架模板语言使用方法详解
2019/07/18 Python
Python时间序列缺失值的处理方法(日期缺失填充)
2019/08/11 Python
css3学习之2D转换功能详解
2016/12/23 HTML / CSS
德国箱包网上商店:koffer24.de
2016/07/27 全球购物
eBay德国站:eBay.de
2017/09/14 全球购物
一级方程式赛车官方网上商店:F1 Store(支持中文)
2018/01/12 全球购物
宝拉珍选官方旗舰店:2%水杨酸精华液,收缩毛孔粗大和祛痘
2018/07/01 全球购物
德国婴儿服装和婴儿用品购买网站:Baby Sweets
2019/12/08 全球购物
.NET初级开发工程师面试题
2014/04/18 面试题
StringBuilder和String的区别
2015/05/18 面试题
行政专员岗位职责
2014/01/02 职场文书
财务担保书范文
2014/04/02 职场文书
工作经历证明书范文
2014/11/02 职场文书
金陵十三钗观后感
2015/06/04 职场文书
销售人员管理制度
2015/08/06 职场文书