python之装饰器讲解***

# -*- coding: utf-8 -*-
"""如果python中的一个类定义了 __call__ 方法,那么这个类它的实例就可以作为函数调用,也就是实现了 () 运算符,即可调用对象协议"""
print("========================__call__-test================================")
class myTest:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __call__(self, x, y):
        self.x, self.y = self.x+x, self.y+y


a = myTest(1, 2)
a(4, 5)
print(a.x, a.y)
#>>>5
#>>>7
print("========================__call__-test=================================\n")

print("========================类(class)做装饰器-1-test==================================")
"""修饰器"""
class myDecoratorsTest:
    def __init__(self, func):           #构造函数的参数为下面定义的函数
        print("myDecoratorsTest __init__ ####1####")              #1
        self.func = func

    def __call__(self, *args, **kwargs):
        print("myDecoratorsTest __call__ ####2####")
        result = self.func(*args, **kwargs)
        return result


@myDecoratorsTest
def add_num(x, y):
    print("add_num  ####3####")
    return x + y

#dt = myDecoratorsTest(add_num)
#dt(1,2)

print(add_num(1, 0))
#>>>1
print("========================装饰器-1-test==================================\n")

print("=======================【第一次修改】==================================")
print("========================装饰器-2-test==================================")
#装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能.装饰器的作用就是为已经存在的对象添加额外的功能
def fun_A(fun):
    print('A')
    fun()

def fun_B():
    print ('B')
    return 1

fn = fun_A(fun_B)
print(fn)       #因为没有返回值所以是None
#>>>A
#>>>B
print("-----------------------------------------------------------------------")

#可以看出,这个程序的运行过程为:
#1.执行函数fun_A,把fun_B当作参数传进去, fun() 这一句 执行了 fun_B, 然后打印 'B' , 返回 1
#2. print ('B') 这一句把 返回的 B 打印出来
#而修饰器的作用:
def fun_AA(fun):#函数本身也是对象,所以可以将函数作为参数传入另一函数并进行调用,而funB是有返回值的,所以结果输出了返回值1.(个人理解)
    print('AA')
    n = 1
    print(fun(n))
@fun_AA
def fun_BB(n):
    print('BB')
    return n+1
#fn = fun_BB
#作用相当于 fn = fun_AA(fun_BB),不过只能放在一个函数或者类定义之前
#需要注意的是,如果fun_BB在fun_AA里没用被调用的话,那fun_BB是不会被执行的,如:

def fun_AAA(fun):
    print ('AAA')

@fun_AAA
def fun_BBB():
    print ('BBB')
    return 1

#>>>AAA
#可以看出,只执行了fun_AAA而fun_BBB没有被执行,因为print('BBB')并没有被打印出来.

#ps:如果fun_AAA不加参数的话,比如直接 def funAAA(): 这样定义,他是会报错的:
#@fun_AAA
#TypeError: fun_AAA() takes 0 positional arguments but 1 was given
#大意是@fun_AAA中的fun_AAA必须要给他提供一个参数,但是你给了0个.
print("========================装饰器-2-test==================================\n")
print("=======================【第二次修改】==================================")
#第一次了解的是一些浅层次的东西,把它深入一下,看个例子:
print("========================一层装饰: 例子==================================")
def outter(func):
    print('---正在装饰-outter---')
    def inner():
        print('---outter-inner---')
        func()
    return inner

@outter
def test1():
    print('---test1---')

test1()
#>>>正在装饰
#可以看出,装饰器 @w1 这一行,其实在函数没有被调用之前已经执行了, 这一句就等于  f1=w1(f1)  所以 w1 函数已经被调用了,返回的是 cou函数的引用,
#所以说如果再调用 f1() ,其实执行的是 cou() ,而真正的 f1 函数的引用现在正被保存在 w1 函数中的 func参数里面,
#(这儿可以当作闭包的一个表现,即当函数中有东西外边还有引用指向它的时候,它并不会立即回收,而是保存了这个函数的空间)

print("\n========================二层装饰: 例子==================================")
def outer1(func):
    print("---正在装饰-outer1----")
    def inner():
        print("---outer1-inner----")
        func()
    return inner

def outer2(func):
    print("---正在装饰-outer2----")
    def inner():
        print("---outer2-inner----")
        func()
    return inner

@outer1
@outer2
def test2():
    print("---test2---")

#>>>---正在装饰-outer2----
#>>>---正在装饰-outer1----
#从运行结果可以看出,首先调用装饰器 outer2,再调用装饰器 outer1,也就是说 运行到 @outer1 这一行,因为在它下面的并不是一个函数,所以 outer1 先暂停,先调用 outer2,
#outer2 装饰完成之后,返回的是 outer2 的 inner 函数的引用,
#outer1 再开始对 outer2 的inner 函数进行装饰. 最后返回的是 outer1 的 inner 函数.
# 如果最后调用 test2()  那么运行结果为:
test2()
# 因为 这个时候调用 test2() 其实 调用的是 outer1 的 inner 函数,所以首先打印 ---outer1-inner---- ,
# 然后 执行 func() 这个 func() 也就是 outer2 的inner, 所以再打印 ---outer2-inner----,
# 下一句 fun() 才是真正的 test2() 函数,打印 ---test2---

print("\n========================装饰有参数的函数: 被装饰的函数有参数的话,可以这样:==================================")
def outer3(func):
    print("---正在装饰-outer3----")
    def inner(*args, **kwargs):
        print("---outer3-inner----")
        func(*args, **kwargs)
    return inner

@outer3
def test3(a):
    print("---test3-a=[%d]---" % a)

test3(123)

#>>>---正在装饰-outer3----
#>>>---outer3-inner----
#>>>---test3-a=[123]---
#在 inner 函数里面加上 接受无名参数和关键字参数,然后 func(*args, **kwargs) 把接收到的参数原封不动的传回 test3 函数里面去,这样 test3 无论有多少个参数,都可以给他传回去.
#那么,如果被装饰的函数有返回值,同样,在 inner里面把函数返回的东西用个变量保存起来,然后 在inner 里面return 即可:

print("\n========================被装饰的函数有返回值:==================================")
def outer4(func):
    print("---正在装饰-outer4----")
    def inner(*args, **kwargs):
        print("---outer4-inner----")
        result = func(*args, **kwargs)  # <----------------------
        return result   # <----------------------
    return inner

@outer4
def test4(a):
    print("---test4-a=[%d]---" % a)
    return a+a,456

res,res2=test4(123)
print(res)
print(res2)
#可以看出 res res2 成功保存了返回的结果
print("\n========================装饰器进行调用,如 @outer5() 后面带个括号=装饰器没有参数==================================")
#如果,对装饰器进行调用,如 @outer5() 后面带个括号, 结果会怎样:
def outer5():
    print("---正在装饰-outer5----")
    def inner(func):
        print("---outer5-inner----")
    return inner

@outer5()
def test5():
    print("---test5---")

#>>>---正在装饰-outer5----
#>>>---test5----
#test5() #Traceback TypeError 'NoneType' object is not callable
#可以看出,虽然没有调用 test5,但是竟然连里面的inner函数也被执行了一遍,因为输出了 ---outer5-inner----
# ,这说明,如果 @outer5() 这样用 ,那么它首先会 把 outer5() 函数执行一遍 , 这个时候返回的是 inner 函数的引用,
#那么,@outer5() 就变成了 @inner 这个时候 再把 test5 传到了inner函数里面开始进行装饰 所以 inner 函数被执行,

print("\n========================装饰器带括号()=并且带有参数==================================")
#利用这个特点,可以在 装饰器中带有参数 ,只不过为了防止调用,需要在外面再加上一层:
def outer6(param1,param2):
    print("---正在装饰-outer6----")
    print("---outer6----[%s]-[%s]" % (param1, param2))
    def outer6_1(func):
        print("---正在装饰-outer6_1----")
        def inner():
            print("---outer6_1-inner----[%s]-[%s]" % (param1,param2))
            func()
        return inner
    return outer6_1

@outer6('param1',"param2")
def test6():
    print("---test6---")

#>>>---正在装饰1----
#过程 1. 首先执行 outer6('hello~')   outer6里面用 nihao 这个变量保存传递的参数,返回的是 outer6_1 的引用
#     2. 装饰器那一行 变成了 @outer6_1 ,然后把 test6 传递进去,调用 outer6_1 开始进行装饰
#   3. 装饰完成后 返回的 是 inner 的引用 所以 现在 test6 = inner
#如果调用 test6() 则正常执行,还可以在 inner 中把传递进去的参数打印出来:
test6()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

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

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

打赏作者

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

抵扣说明:

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

余额充值