浅析:python中的装饰器

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/rusi__/article/details/100122705

简要

  • 装饰器的作用:在不改变代码本身添加功能。
  • 装饰器其实就是函数引用传递的过程。(具体参考代码片1理解)
  • 装饰器在没调用函数前就已经执行代码并装饰了。(具体参考代码片2理解)
  • 参数的传递要谨遵“怎样来就怎样回去”(具体参考代码片3理解)
  • 被装饰函数如果有返回值的话就需要return哦(具体参考代码片3理解)
  • 如果多个装饰器装饰一个函数,装饰是“由下向上”,代码执行是“由上到下”(具体参考代码片4)
  • 如果装饰器自己还要传递参数的话,那么就再套一层“def即可”。(具体参考代码片5理解)
  • 类也是可以当作装饰器的(具体参考代码片6理解)

代码1:没有参数没有返回值的装饰器

重点是:test1 = set_func(test1)

def set_func(func):
	def call_func():
		print("----quanxianyanzheng1-----")
		print("-----quanxianyanzheng2----")
		func()
	return call_func

# @set_func 等价于 test1 = set_func(test1)
def test1():
	print("----test1----")

# ret = set_func(test1)
# ret()

test1 = set_func(test1) # 使fun形参指向了最初的test1函数
test1()

代码2:装饰器在调用函数之前就已经装饰上了。

def set_func(func):
    print("装饰器在函数调用之前已经装饰了")
    def call_func(a_num):
        print("----quanxianyanzheng1-----")
        print("-----quanxianyanzheng2----")
        func(a_num)

    return call_func


@set_func  # 等价于 test1 = set_func(test1)[此时执行代码并不会跳过]
def test1(num):
    print("----test1----%d" % num)

@set_func
def test2(num):
    print("----test2----%d" % num)


# test1(100)   # 因为装饰器的存在,所以就直接调用test1引用的call_func函数
# test2(200)


代码3:不定长且有返回值的函数的装饰(通用装饰器的写法)

def set_func(func):
    def call_func(*args,**kwargs):  # def call_func(*args,**kwargs):  参数也可以这样写
        print("----quanxianyanzheng1-----")
        print("-----quanxianyanzheng2----")
        # print(args,kwargs)
        # func(args, kwargs)  # 不行,相当于传递了2个参数 :1个元组,1个字典
        return func(*args,**kwargs)  # 拆包,拆成-->100,200,300,mm=100,bb=200
    return call_func


@set_func  # 等价于 test1 = set_func(test1)[此时执行代码并不会跳过]
def test1(num,num2,*args,**kwargs):
    # print(type(num))
    print("----test1----%d" % num)
    print("----test1----%d" % num2)
    print("----test1----", args)
    print("----test1----", kwargs)
    return "ok"


ret=test1(100,200,300,mm=100,bb=200)   # 因为装饰器的存在,所以就直接调用test1引用的call_func函数
print(ret)



# 这里就是通用的装饰器了。
# 如果一个函数没有返回值的话,返回的便是none。


代码4:多个装饰器装饰一个函数

def add_qx(func_01):
	print("---开始进行装饰权限1的功能---")

	def call_func(*args, **kwargs):
		print("---这是权限验证1----")
		return func_01(*args, **kwargs)
	return call_func


def add_xx(func_02):
	print("---开始进行装饰xxx的功能---")

	def call_func(*args, **kwargs):
		print("---这是xxx的功能----")
		return func_02(*args, **kwargs)
	return call_func


@add_qx
@add_xx
def test1():
	print("------test1------")


test1()


# 装饰器装饰的是函数的引用,当qx发现下方不是函数的引用时,便不会装饰,然后当xx变为函数的引用时,qx才会装饰。
# 执行的时候,便是正常执行了,就像单独只有一个装饰器的时候会先执行装饰器一样,所以也会先执行qx再执行xx。



代码5:装饰器如果自己还要有参数。

def set_level(level_num):  # 接收装饰器的参数
    def set_func(func):  # 接收函数的引用
        def call_func(*args, **kwargs):
            if level_num == 1:
                print("----权限级别1,验证----")
            elif level_num == 2:
                print("----权限级别2,验证----")
            return func()

        return call_func

    return set_func


# 带有参数的装饰器装饰过程分为2步:
# 1. 调用set_level函数,把1当做实参
# 2. set_level返回一个装饰器的引用,即set_func
# 3. 用返回的set_func对test1函数进行装饰(装饰过程与之前一样)
@set_level(1)
def test1():
    print("-----test1---")
    return "ok"


@set_level(2)
def test2():
    print("-----test2---")
    return "ok"


test1()
test2()


代码6:用类来当装饰器。

重点是:
1.创建对象会调用__init__方法,而__init__方法负责接收这个参数(函数的引用)。
2.实例对象() 会自动调用__call__方法

class Test(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("这里是装饰器添加的功能.....")
        return self.func(*args, **kwargs)  # 拆包 拆成---->1, 2, 3,mm=66


@Test  # 相当于get_str = Test(get_str),get_str成了一个实例对象。 # 最多会让你用类的静态方法当装饰器(静态方法存在一个闭包这样理解便好了)
def get_str(num,*args, **kwargs):
    print(num,args, kwargs)
    return "haha"


print(get_str(1, 2, 3, mm=66))  # 实例对象(),便会调用__call__方法


补充

  • 如果需要用类中的静态方法作为装饰器的话(谁会这么无聊?好吧,也许实际需求就会那么无聊。),我们简单理解静态方法中有个闭包就可以了。
  • 闭包是什么?闭包就是def套def;这不是装饰器吗?是啊,这就是啊!-。-

猜你喜欢

转载自blog.csdn.net/rusi__/article/details/100122705