Python 装饰器-上

目  录

1. 用户自定义的装饰器-函数

1.1 无参装饰器

1.1.1 被修饰的函数没有参数

1.1.2 被修饰的函数有参数

1.2 有参装饰器

1.2.1 被修饰的函数没有参数

1.2.1 被修饰的函数有参数

2. 用户自定义的装饰器-类

2.1 类装饰器实现原理-特殊的类方法 __call__

 2.2 简单的没有参数的类装饰器

2.2.1 被装饰的函数没有参数

2.2.1 被装饰的函数有参数

 2.3 带有参数的类装饰器


建议初学者在看本章之前,先看一下这两个小节,有经验的同学请随意。

Python 函数式编程 Functional Programming-上

Python 函数式编程 Functional Programming-下

关于装饰器的总共三篇,分别是:

Python 装饰器-上

Python 装饰器-中

Python 装饰器-下

        Python  装饰器

        定义:是一种可以装饰其它对象的工具,本质上是一个可调用的对象(callable),所以装饰器一般可以由函数、类来实现。
        用途:装饰器本身需要接受一个被装饰的对象作为参数,该参数通常为函数、方法、类等对象。
        返回值:装饰器需要返回一个对象,该对象可以是经过处理的原参数对象、一个包装且类似原参数的对象;或者返回一个不相干内容。

Python 装饰器类别,积累中.........

装饰器来源

装饰器类别

实现原理

用户自定义

函数

函数的闭包特性

一般依靠类内部的__call__方法,可以修饰类、函数,分无参数和有参数两种

内置

@property

@x.setter

@x.getter

 @x.deleter

特性装饰器

@classmethod

类方法装饰器

@staticmethod

静态方法装饰器


 

1. 用户自定义的装饰器-函数

1.1 无参装饰器

1.1.1 被修饰的函数没有参数

        装饰器、被装饰函数都不带参数,这是一种最简单的情况。个人觉得实际运行中绝大多数被修饰的函数都是有参数的。

        先说一个非常简单的装饰器,它甚至没有定义新函数,但是确实实现了装饰器的功能

def wrap(func):
    print("Happy birthday!")
    return(func)

@wrap
def f1():
    print("Everyone is OK !")
    
f1()

 

 稍微复杂一点的如下:

# 定义装饰器函数 logger
def logger(func):
  #定义一个嵌套函数
  def wrapper(*args, **kw):
    print("*"*50)
    print("Function begin!")
    # 真正执行的是这行。
    func()
    print("Function end!")
  return wrapper
 
@logger
def f1():
    print("This is function 1 !")

f1()

运行结果:

1.1.2 被修饰的函数有参数

        被修饰的函数有参数,下面是一个简单的例子,不知道大家注意到没有,f1 函数是有返回值的,但是被装饰之后,却没有返回值。

# 定义装饰器函数 logger
def logger(func):
  #定义一个嵌套函数
  def wrapper(*args, **kw):
    print("*"*50)
    print("Function begin!")
    
    # 真正执行的是这行。
    func(*args, **kw)
    
    print("Function end!")
  return wrapper
 
@logger
def f1(a,b,c=3):
    print("This is function 1 !")
    res=a+b+c*10
    print(res)
    return(res)

print("+"*20) #第一个被执行的语句
a=f1(100,50,1) #接下来执行的语句
print("-"*20) # 最后执行的语句
print(a) # 可以看到被装饰后,函数返回值是 None,原因在于 wrapper 函数中没有写返回值。

运行结果

         如果大家注意到 f1() 被装饰后缺少返回值,那是因为闭包函数 wrapper 中只是执行了被当作参数传进来的函数,并没有把执行结果传递出去,简单如下修改一下即可。

# 定义装饰器函数 logger
def logger(func):
  #定义一个嵌套函数
  def wrapper(*args, **kw):
    print("*"*50)
    print("Function begin!")
    
    # 真正执行的是这行。
    res=func(*args, **kw) #先保存函数返回值
    
    print("Function end!")
    return(res) #此处将 func 返回值传递出去
  return wrapper
 
@logger
def f1(a,b,c=3):
    print("This is function 1 !")
    res=a+b+c*10
    print(res)
    return(res)

print("+"*20) #第一个被执行的语句
a=f1(100,50,1) #接下来执行的语句
print("-"*20) # 最后执行的语句
print(a) # 这时候被装饰的函数返回值也被传递出来

 

1.2 有参装饰器

        这时候要对原有装饰器进行封装,并返回一个装饰器,即一个含有参数的闭包函数。

1.2.1 被修饰的函数没有参数

        对 1.1.1 的代码进行修改。

# 定义装饰器函数 logger

def logger(flag):
    def show(func):
        def wrapper(*args, **kw):
            if(flag==True):
                print("flag is True,We use * to show!")
                print("*"*50)
            else:
                print("flag is False,We use + to show!")
                print("+"*50)
                

            print("Function begin!")
            
            # 真正执行的是这行。
            func() 
            
            if(flag==True):
                print("flag is True,We use * to show!")
                print("*"*50)
            else:
                print("flag is False,We use + to show!")
                print("+"*50)
                
            print("Function end!")
        return(wrapper)
    return(show)
 
@logger(True)
def f1():
    print("This is function 1 !")

@logger(False)
def f2():
    print("This is function 2 !")
    
f1()
f2()

1.2.1 被修饰的函数有参数

          假如装饰器有参数,被装饰的函数也有参数,那么其实很简单,相对于 1.2.1 的代码,只需要改动一行代码即可。

# 定义装饰器函数 logger

def logger(flag):
    def show(func):
        def wrapper(*args, **kw):
            if(flag==True):
                print("flag is True,We use * to show!")
                print("*"*50)
            else:
                print("flag is False,We use + to show!")
                print("+"*50)
                

            print("Function begin!")
            
            # 真正执行的是这行。
            func(*args, **kw) #~~~~~~~~~~~~~改这一行即可~~~~~~~~~~
            
            if(flag==True):
                print("flag is True,We use * to show!")
                print("*"*50)
            else:
                print("flag is False,We use + to show!")
                print("+"*50)
                
            print("Function end!")
        return(wrapper)
    return(show)
 
@logger(True)
def f1(a,b):
    print("This is function 1 !")
    print(a+b)

@logger(False)
def f2(a,b,c,d):
    print("This is function 2 !")
    print(a*b+c+d)
    
f1(100,99)
print("---分割线---"*5)
f2(100,3,20,1)

2. 用户自定义的装饰器-类

2.1 类装饰器实现原理-特殊的类方法 __call__

      Python 中有一个非常特殊的类方法 __call__,我们知道一般的用户定义函数、内置函数、方法都是可调用 callable 对象,那么类实例是不是可调用 callable 对象呢。只要这个类实现了 __call__ 方法,它就是可调用 callable 对象,否则不是。换句话说,我们可以把这个类型的对象当作函数来使用,相当于 重载了括号运算符。

        先看看没有实现方法 __call__的类,可以用内置函数 callable() 去判断它的实例是否是可调用 callable 对象。

class Man():
    def __init__(self,name,age):
        self.name=name
        self.age=age
        '''
    def __call__(self,name,age):
        print("Name is ",name)
        print("Age is ",age)
        '''
man=Man("Ivy",39)
callable(man)

 

        如果实现了 方法 __call__,情况就不一样了

class Man():
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __call__(self,name,age):
        print("Name is ",name)
        print("Age is ",age)
        
man=Man("Ivy",39)
callable(man)

        在这个时候,就可以使用 Man 类的实例实现函数的功能,这是实现类装饰器的原理,如下:

 2.2 简单的没有参数的类装饰器

2.2.1 被装饰的函数没有参数

        下面是一个简单的,没有参数的类装饰器,用来装饰一个普通的没有参数的函数。

# 定义装饰器函数 logger
class Logger(object):
    def __init__(self, f):
        self.f = f
    def __call__(self):
        print("Logger start")
        self.f()
        print("Logger end")

@Logger
def func1():
    print("func1")

@Logger
def func2():
    print("func2")

func1()
func2()

运行结果如下: 

2.2.1 被装饰的函数有参数

        只需要简单的在 __call__ 类方法中加上参数即可

# 定义装饰器函数 logger
class Logger(object):
    def __init__(self, f):
        self.f = f
    def __call__(self,*args, **kw):
        print("Logger start")
        self.f(*args, **kw)
        print("Logger end")

@Logger
def func1(a,b):
    print("func1")
    print(a+b)

@Logger
def func2(a,b,c,d):
    print("func2")
    print(a*b*c-d)

func1(100,99)
func2(2,3,11,5)

 2.3 带有参数的类装饰器

        类装饰器带有参数时候稍微复杂一点

# 定义装饰器函数 logger
class Logger(object):
    def __init__(self, level):
        self.level = level
    def __call__(self,func,*args, **kw):
        def wrapper(*args, **kwargs):
            print("[{0}]: enter {1}()".format(self.level, func.__name__))
            return func(*args, **kwargs)
        return wrapper

@Logger(True)
def func1(a,b):
    print("func1")
    print(a+b)

@Logger(False)
def func2(a,b,c,d):
    print("func2")
    print(a*b*c-d)

func1(100,99)
func2(2,3,11,5)

'''

要是大家觉得写得还行,麻烦点个赞或者收藏吧,想个博客涨涨人气,非常感谢!

'''

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江南野栀子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值