python_装饰器入门教程哦

什么是装饰器?

简单来说,可以把装饰器理解为一个包装函数的函数,它一般将传入的函数或者是类做一定的处理,返回修改之后的对象。
所以我们能够在不修改原函数的基础上,在执行原函数前后去执行别的代码,比较常用的场景有日志插入,事务处理

应用场景

常用于缓存、权限校验、日志记录、性能测试、事务处理等场景

例子

我们知道,在python中函数也是被视为对象的,可以作为参数传递,那么假如把计算机耗时操作 独立为一个单独的函数,然后只要往里头传入需要计算耗时的函数1 就可以不用往函数1中额外添加计算耗时的语句啦

def calc_spend_time(func,*args,**kargs):
  start_time = datetime.datetime.now()
  result = fun(*args,**kargs)
  end_time = datetime.datetime.now()
  print "result:",result,"used:",(end_time - start_time).microseconds
  
def calc_add(a,b):
  return a + b
  
calc_spend_time(calc_add,1,1)

看起来也不错,负责计算的函数不用更改代码,只需调用的时作为参数传给计算时间差的函数。
但就是这,调用的时候形式变了,不再是clac(1,2),而是calc_spend_time(clac_add,1,2),万一calc_add大规模被调用,那么还得一处一处找,然后修改过来,还是很麻烦???

那么可以在calc_spend_time()里把传入的calc_add()包装一下,然后返回包装后的新的函数,再将其赋值给clac_add,那么calc_add()的效果就和calc_spend_time(calc(),*args,*kwargs)的效果一样

import datetime
def calc_spend_time(func):
	@wraps(func) # 把new_func的属性值赋给new_func,例如调用func.__name__ 是显示的是func,还是new_fun
	def new_func(a,b):
	   start_time = datetime.datetime.now()
	   result = func(a,b)
	   end_time = datetime.datetime.now()
	   print "result:",result,"used:",(end_time - start_time).microseconds
	return new_func 
	
def calc_add(a,b):
 return a + b
 
calc_add = calc_spend_time(calc_add)
calc_add(1,2) 

语法糖:
上面的列子就是装饰器的概念,包含函数的函数<函数内部定义一个函数,这个函数需要调用某一个函数>,上面的例子还可以更简洁

import datetime

def calc_spend_time(func):
	def new_func(a,b):
	   start_time = datetime.datetime.now()
	   result = func(a,b)
	   end_time = datetime.datetime.now()
	   print "result",result,"used:",(end_time - start_time).microseconds,"us"
	return new_func
 
 @calc_spend_time
 def calc_add(a,b):
  return a+b
  
 calc_add(1,2)

分析

@calc_spend_time就是语法糖,它的本质就是:calc_add = calc_spend_time(calc_add)

无参数的函数装饰器

import datetime
def calc_spend_time(func):
	def new_func(*args,**kargs):
	  start_time = datetime.datetime.now()
	  result = func(*args,**kargs)
	  end_time = datetime.datetime.now()
	  print "result:",result,"used:",(end_time - start_time).microseconds,"us"
	result new_func
	
 @calc_spend_time
 def calc_add(a,b)return a+b
  
 @calc_spend_time
 def calc_diff(a,b):
  return a - b
  
 calc_add(a=1,b=2)
 calc_diff(1,2)

分析

*args:把所有的参数按出现的顺序打包成tuple
**kargs:把所有的key=value形式的参数打包成一个dict

带参数的函数装饰器_1

假如我们需要知道函数的一些额外的信息,假如函数作者,可以通过给装饰器函数增加参数来实现

import datetime
def calc_spend_time(author):
	def first_deco(func):
		def new_func(*args,**kargs):
		   start_time=datetime.datetime.now()
		   result = func(*args,**kargs):
		   end_time = datetime.datetime.now()
		   print author,"result:",result,"used:",(end_time - start_time).microseconds,"us"
		   
		  return new_func
		  
	return first_deco

@calc_spend_time('author_1') 
def calc_add(a,b):
 return a+b

@calc_spend_time('author_2')
def calc_diff(a,b):
 return a-b
 
 # 0. calc_spend_time('author_1')
 # 1. calc_add=first_func(calc_add)
 # 2. cal_add(1,2) =>> new_func(1,2)
 
calc_add(a=1,b=2) 
calc_diff(1,2)

带参数的函数装饰器_2

import time
from functools import wraps

DEFAULT_FMT = '[{elapsed:.8f}s] {name}({all_args_str}) -> {result}'


# 实现自定义日志输出格式
def clock(fmt=DEFAULT_FMT):
    def decorate(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            t0 = time.perf_counter()
            result = func(*args, **kwargs)  # 无法捕捉默认参数
            elapsed = time.perf_counter() - t0
            name = wrapper.__name__
            print(name)
            args_str = ', '.join(repr(arg) for arg in args)  # 读取传入的元组参数
            kwargs_str = ', '.join(f'{k}={w}' for k, w in sorted(kwargs.items()))  # 读取传入的字典参数
            all_args_str = ', '.join(astr for astr in [args_str, kwargs_str] if astr)  # 去掉元组参数和字典参数为空的值 
            print(fmt.format(**locals()))
            return result

        return wrapper

    return decorate


@clock()
def factorial_default_fmt(n: int) -> int:
    return 1 if n < 2 else n * factorial_default_fmt(n - 1)

factorial_default_fmt(4)

python内置装饰器

python内置的装饰器有三个:

staticmethod
classmethod
property

staticmethod
把类中的方法定义为静态方法,使用staticmethod装饰的方法可以使用类或者类的实例对象来调用,不需要传入self

class Human(object):
 "docstring for Human"
 def __int__(self):
  super(Human,self).__int__()
  
 @staticmethod
 def say(message):
  if not message:
    message = 'hello'
  print 'I say %s'% message
  
 def speak(self,message):
  self.say(message)
  
Human.say(None)
human = Human()
human.speak('hi')

输出:

I say hello
I say hi

classmmethod
把类中的方法定义为类的方法,
使用classmethod装饰的方法可以使用类的或者类的实例对象来调用,
并将该class对象隐式的作为第一个参数传入

class Human(object):
 """docstring for Human"""
 def __int__(self):
  super(Human,self).__init__()
  self.message = '111'
  
 def say(message):
  if not message:
    message = "hlleo"
  print "I say %s" %message
  
 @classmethod
 def speak(cls,message):
  if not message:
    message = 'hello'
  cls.say(message)
  
human = Human()
human.speak('hi')
输出:
I say hello
I say hi

property
把方法变成属性

class Human(object):
 def __init__(self,value):
  super(Human,self).__init__()
  self.arg = value
  
 @property
 def age(self):
  return self._age
human = Human(20)
print human.age

巨人的肩膀

Python装饰器的通俗理解

猜你喜欢

转载自blog.csdn.net/sinat_40701582/article/details/105922709
今日推荐