python 装饰函数2

#!/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]")
原文地址:https://www.cnblogs.com/1314520xh/p/12833640.html