云上的天涯

导航

python 装饰器的理解以及类装饰器

python装饰器的作用就是在不改变原有函数结构的情况下给该函数增加一个新功能,就是不入侵到原来函数里面修改代码给其增加一个新功能

先看代码

def out(fn):
    def inner(*args, **kwargs):
        print("这个是个装饰器,是用来装饰其他函数用的")
        ret = fn(*args, **kwargs)
        print("******************")
        return ret
    return inner

上面是个装饰器函数

下面是被装饰的函数

def test(name):
    print("这个是fn函数,是被装饰的")
    return name

怎么调用呢?

常规方法是这样,把下面的test函数以参数方式传入到上面的装饰器函数,也就是下面这样的方式

foo = out(test)
print(foo("Bob"))
#我们看下执行结果
这个是个装饰器,是用来装饰其他函数用的
这个是fn函数,是被装饰的
******************
Bob

#在没有改变test函数代码情况下给test函数增加了新功能

但是以上的调用方式太过于麻烦,有没有简单点的,答案是有的,就是用以下方式调用

@out
def test(name):
    print("这个是fn函数,是被装饰的")
    return name
##上面的@out方式在python中是叫做语法糖的方式,其实就等价于以下的调用方式
#####
test = out(test) ##==>把out(test)的返回值再赋值给test,想想out(test)的返回值是什么?对了,是inner函数,所以此时test 也就是inner函数了
####
print(test("Bob")) ###==>同理,这里打印出来是是inner函数的返回值,以及inner函数的print函数所打印出的东西,由于Inner函数同时也返回了test函数的返回值,所以就达到了,在不改变test函数情况下,给test函数增加了新功能

我们来看个完整的代码块,以及执行结果

def out(fn):
    def inner(*args, **kwargs):
        print("这个是个装饰器,是用来装饰其他函数用的")
        ret = fn(*args, **kwargs)
        print("******************")
        return ret
    return inner

@out
def test(name):
    print("这个是fn函数,是被装饰的")
    return name
@out
def test_other(name):
    print("这是另外一个被装饰的函数")
    return name

print(test("Bob"))
print("********我是华丽的分割线******")
print(test_other("Joke"))

########执行结果如下###########

这个是个装饰器,是用来装饰其他函数用的
这个是fn函数,是被装饰的
******************
Bob
********我是华丽的分割线******
这个是个装饰器,是用来装饰其他函数用的
这是另外一个被装饰的函数
******************
Joke

看到了吧,两个函数都被正确的装饰了

接下来我们看点有趣的东西,这是我忽然想到的

先看代码块

def out(args):
    def inner(fn):
        print("这个是个装饰器,是用来装饰其他函数用的")
        ret = fn(args)
        print("******************")
        return ret
    return inner

def test(name):
    print("这个是fn函数,是被装饰的")
    return name

foo = out("Joke")
print(foo(test))

#####看下执行结果#####
这个是个装饰器,是用来装饰其他函数用的
这个是fn函数,是被装饰的
******************
Joke

是不是很神奇啊,out函数接收常规参数,inner函数接收函数参数也就是func参数

首先 foo = out("Joke"),先传入一个常规str值

然后 print(foo(test)) 打印出foo的返回值,这里的逻辑很重要我们来捋下==>>

foo = out("Joke")等价于把out("Joke")返回值赋给foo,那么这时候foo就等价于inner函数,只是这个args函数给传进去,但是还没使用,你给函数传参是一回事,你用与不用又是另一回事,对不对?所以这里没什么可纠结的吧,然后我们print(foo(test))就等价于把test函数以参数方式传入到inner函数里面,由于你已经传入到一个args了,所以了test函数是可以拿到这个参数的,不明白的建议看下函数的作用域这块,ret = fn(args) 就等价于test(name)明白了吧,最后return ret就得到了test(name),这和上面的装饰器实现方式其实是一致的,只是参数位置调换了而已,装饰器的out的参数是函数,inner参数是常规str参数,这个正好对换位置了,传参方式也相应改变了,我不知道这个有什么用,但是只是想试试,那么我们还能用@out方式来装饰吗,试试就知道了

def out(args):
    def inner(fn):
        print("这个是个装饰器,是用来装饰其他函数用的")
        ret = fn(args)
        print("******************")
        return ret
    return inner

@out
def test(name):
    print("这个是fn函数,是被装饰的")
    return name
print(test("Bob"))

###来看下结果###
这个是个装饰器,是用来装饰其他函数用的
Traceback (most recent call last):
  File "E:/python_learn/装饰器.py", line 13, in <module>
    print(test("Bob"))
  File "E:/python_learn/装饰器.py", line 4, in inner
    ret = fn(args)
TypeError: 'str' object is not callable
最后一句告诉你str是不能被调用的,看来更换参数位置后,装饰器也不能这样调用了,这样有助于大家更快理解装饰器。

 

posted on 2018-06-20 10:11  云上的天涯  阅读(217)  评论(0编辑  收藏  举报