#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Tue May 5 21:40:49 2020 @author: root 装饰器语法糖 装饰器的使用方法很固定: 1.先定义一个装饰函数(帽子)(也可以用类、偏函数实现) 2.再定义你的业务函数、或者类(人) 3.最后把这顶帽子带在这个人头上 案例:https://www.jb51.net/article/168276.htm """ #2日志打印器 # 首先是日志打印器。 # 它要实现的功能是 # 在函数执行前,先打印一行日志告知一下主人,我要执行函数了。 # 在函数执行完,也不能拍拍屁股就走人了,咱可是有礼貌的代码,再打印一行日志告知下主人,我执行完啦。 def logger(func): def wrapper(*args,**kwargs): print ('start--------------') func(*args,**kwargs) print ('end----------------') return wrapper @logger def add(x,y): print('{} + {} = {}'.format(x, y, x+y)) add(20,90) #3 入门用法:时间计时器 import time def timer(func): def wrapper(*args,**kw): t1=time.time() func(*args,**kw) t2=time.time() cost_time=t2-t1 print ("花费时间:{}秒".format(cost_time)) return wrapper @timer def want_sleep(sleep_time): time.sleep(sleep_time)
want_sleep(10) # 3进阶用法:带参数的函数装饰器 def say_hello(contry): def wrapper(func): def deco(*args,**kwargs): if contry=='china': print ("ni hao") elif contry=='american': print ('hello') else: return func(*args,**kwargs) return deco return wrapper @say_hello('american') def american(): print ('----------------china') @say_hello('china') def chinese(): print ('----------------zhongguo') american() print ('---------------') chinese() # 高阶用法:不带参数的类装饰器 """ 以上都是基于函数实现的装饰器,在阅读别人代码时,还可以时常发现还有基于类实现的装饰器。 基于类装饰器的实现,必须实现 __call__ 和 __init__两个内置函数。 __init__ :接收被装饰函数 __call__ :实现装饰逻辑 """ class logger(object): def __init__(self,func): self.func=func def __call__(self,*args,**kwargs): print("[INFO]: the function {func}() is running..." .format(func=self.func.__name__)) return self.func(*args,**kwargs) @logger def say(something): print ("say {}!".format(something)) say('hello') # 高阶用法:带参数的类装饰器 # 上面不带参数的例子,你发现没有,只能打印INFO级别的日志,正常情况下,我们还需要打印DEBUG WARNING等级别的日志。 这就需要给类装饰器传入参数,给这个函数指定级别了。 # 带参数和不带参数的类装饰器有很大的不同。 # __init__ :不再接收被装饰函数,而是接收传入参数。 # __call__ :接收被装饰函数,实现装饰逻辑 class logger2(object): def __init__(self,level='INFO'): self.level=level def __call__(self,func): def wrapper(*args,**kwargs): print("[{level}]: the function {func}() is running..." .format(level=self.level, func=func.__name__)) func(*args, **kwargs) return wrapper @logger2(level='warning') def say(something): print ("say {}!".format(something)) say('hello') # 内置装饰器:property # 以上,我们介绍的都是自定义的装饰器。 # 其实Python语言本身也有一些装饰器。比如property这个内建装饰器,我们再熟悉不过了。 # 它通常存在于类中,可以将一个函数定义成一个属性,属性的值就是该函数return的内容。 class Student(object): def __init__(self, name): self.name = name self.name = None @property def age(self): return self._age @age.setter def age(self, value): if not isinstance(value, int): raise ValueError('输入不合法:年龄必须为数值!') if not 0 < value < 100: raise ValueError('输入不合法:年龄范围必须0-100') self._age=value @age.deleter def age(self): del self._age XiaoMing = Student("小明") # 设置属性 XiaoMing.age = 25 print (XiaoMing.name) print (XiaoMing.age) # example2: class Student: def __init__(self,name): self.name=name @property def math(self): return self._math @math.setter def math(self,value): if 0<=value<=100: self._math=value else: raise ValueError("Valid value must be in [0, 100]")
实现propetry 装饰器
class TestProperty(object):
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fset = fset
self.fget = fget
self.fdel = fdel
self.__doc__ = doc
def __get__(self, obj, objtype=None):
print('---in --get')
if obj is None:
return self
if self.fget is None:
raise AttributeError
return self.fget(obj)
def __set__(self,obj,value):
print ('----in --set')
if self.fset is None:
raise AttributeError
self.fset(obj,value)
def __delete__(self,obj):
print ('---in ---delete')
if self.fdel is None:
raise AttributeError
self.fdel(obj)
def getter(self,fget):
print ('in getter')
return type(self)(fget,self.fset,self.fdel,self.__doc__)
def setter(self,fset):
print ('in setter')
return type(self)(fset,self.fget,self.fdel,self.__doc__)
def deleter(self,fdel):
print ('in fdel')
return type(self)(fdel,self.fget,self.fset,self.__doc__)
测试一下:
class Student: def __init__(self, name): self.name = name # 其实只有这里改变 @TestProperty def math(self): return self._math @math.setter def math(self, value): if 0 <= value <= 100: self._math = value else: raise ValueError("Valid value must be in [0, 100]")