开发手册 欢迎您!
软件开发者资料库

Python 自定义装饰器使用写法及示例代码

Python中除了有内置装饰器(@property、@staticmethod、@classmethod),还可以自定义装饰器,本文主要介绍一下自定义装饰器的使用写法,以及相关的示例代码。

1、Python装饰器简介

python的装饰器就是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。简单的说装饰器就是一个用来返回函数的函数。

它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题,代码很好地重用。简单理解,装饰器的作用就是为已经存在的对象添加额外的功能。

2、Python内置装饰器

相关文档Python内置装饰器(@property、@staticmethod、@classmethod)使用及示例代码

3、Python装饰器语法及原理

python提供了@符号作为装饰器的语法糖,使我们更方便的应用装饰函数。但使用语法糖要求装饰函数必须return一个函数对象。因此我们将上面的func函数使用内嵌函数包裹并return

装饰器相当于执行了装饰函数use_loggin后又返回被装饰函数bar,因此bar()被调用的时候相当于执行了两个函数。等价于use_logging(bar)()

def use_logging(func):  def _deco():    print("%s is running" % func.__name__)    func()  return _deco@use_loggingdef bar():  print('i am bar')bar()

4、Python装饰器的使用

1)装饰器修饰带参数方法

def use_logging(func):
def _deco(a,b):
print("%s is running" % func.__name__)
func(a,b)
return _deco
@use_logging
def bar(a,b):
print('i am bar:%s'%(a+b))
bar(1,2)

2)装饰器修饰不确定参数个数方法

def use_logging(func):
def _deco(*args,**kwargs):
print("%s is running" % func.__name__)
func(*args,**kwargs)
return _deco
@use_logging
def bar(a,b):
print('i am bar:%s'%(a+b))
@use_logging
def foo(a,b,c):
print('i am bar:%s'%(a+b+c))
bar(1,2)
foo(1,2,3)

3)带参数的装饰器

#! /usr/bin/env python# -*- coding:utf-8 -*-# __author__ = "TKQ"def use_logging(level):  def _deco(func):    def __deco(*args, **kwargs):      if level == "warn":        print "%s is running" % func.__name__      return func(*args, **kwargs)    return __deco  return _deco@use_logging(level="warn")def bar(a,b):  print('i am bar:%s'%(a+b))bar(1,3)# 等价于use_logging(level="warn")(bar)(1,3)

4)使用functools.wraps解决原函数的元信息问题

import functoolsdef use_logging(func):  @functools.wraps(func)  def _deco(*args,**kwargs):    print("%s is running" % func.__name__)    func(*args,**kwargs)  return _deco@use_loggingdef bar():  print('i am bar')  print(bar.__name__)bar()#result:#bar is running#i am bar#bar 

5、装饰器同时兼容带参数和不带参数的情况

import functoolsdef use_logging(arg):  if callable(arg):#判断传入的参数是否是函数,不带参数的装饰器调用这个分支    @functools.wraps(arg)    def _deco(*args,**kwargs):      print("%s is running" % arg.__name__)      arg(*args,**kwargs)    return _deco  else:#带参数的装饰器调用这个分支    def _deco(func):      @functools.wraps(func)      def __deco(*args, **kwargs):        if arg == "warn":          print "warn%s is running" % func.__name__        return func(*args, **kwargs)      return __deco    return _deco@use_logging("warn")# @use_loggingdef bar():  print('i am bar')  print(bar.__name__)bar()

6、类的装饰器的使用

class loging(object):  def __init__(self,level="warn"):    self.level = level  def __call__(self,func):    @functools.wraps(func)    def _deco(*args, **kwargs):      if self.level == "warn":        self.notify(func)      return func(*args, **kwargs)    return _deco  def notify(self,func):    # logit只打日志,不做别的    print "%s is running" % func.__name__@loging(level="warn")#执行__call__方法def bar(a,b):  print('i am bar:%s'%(a+b))bar(1,3)#继承扩展类的装饰器class email_loging(Loging):  '''  一个loging的实现版本,可以在函数调用时发送email给管理员  '''  def __init__(self, email='admin@myproject.com', *args, **kwargs):    self.email = email    super(email_loging, self).__init__(*args, **kwargs)  def notify(self,func):    # 发送一封email到self.email    print "%s is running" % func.__name__    print "sending email to %s" %self.email@email_loging(level="warn")def bar(a,b):  print('i am bar:%s'%(a+b))bar(1,3)

相关文档Python中@staticmethod和@classmethod区别及使用示例代码