Python笔记-关于装饰器写法的理解

2018-03-18  本文已影响17人  绿箭ML

实际上就是闭包的"快捷写法"

学习的过程中主要是要容易搞混参数的问题
1.装饰器有参数
2.被修饰的函数也有参数
3.返回的函数有参数

主要是要讨论这三个问题,首先,看下默认情况:
调用被修饰的函数前会找把这个函数作为参数传递给装饰器,然后装饰器返回一个闭包,然后再调用

#这货是个装饰器,我们主要是,让它输出"小明 说了啥"

def say(person):
    def  inner(what):
         print(person()+"说了"+what)
    return inner

@say
def  xm():
    return "小明"

xm("你好")

首先有点好奇的是:
函数xm不是没有参数的么,怎么调用的时候又带了个,这样的确让人摸不着头脑

我们尝试下一句句理解
1.xm是一个不带参数的函数
2.当say修饰它的时候,会先调用say,默认把xm作为参数传递给say(先不管xm参数的去向,前后再撸一撸。然而这里的xm并没有参数。哇咔咔(︶︿︶)=凸)
3.我们在say函数中定义了一个函数inner,say执行结束后把inner返回,也就是调用完say后返回的对象是函数对象
4.我们看看inner,它有一个参数what,实际上最后返回的函数形如func(arg)这样的格式(大概猜到后面跟的参数是怎么来的吧),xm()它压根不是调用xm!!!惊喜不惊喜,意外不意外(头点点笑嘻嘻,一口老血mmp),为什这么说,因为,xm作为参数传递给say,点不调用xm,完全看say怎么写,不信是把,我们写个例子

#请注意,此处未调用func
def say(func):
    def inner(what):
        print(what)
    return inner

def  xm():
    return "小明"
xm("喵喵喵?")

mmp,压根没调用xm,最后的写法果然想迷惑老夫?d(ŐдŐ๑)实际上等价于写成的

def say(func):
    def inner(what):
        print(what)
    return inner

def  xm():
    return "小明"
say(xm)("喵喵喵")

好了,写到这里的时候,自己基本吧简单的那种情况捋顺了,现在问题来了,即使写一个很简单的装时期,也涉及到三个参数,如果每一个参数都有函数,那么,就更加头大了,笑嘻嘻(MMP)


多个参数的情况

条件:
1.装饰器有参数
2.被修饰的函数有参数
3.闭包也有参数

形如这样的


@say("小明")
def who(name):
  return name

笑嘻嘻(mmp),我的装饰器要怎么写,好,尝试下怎么写的

#coding:utf-8
def say(name):
    def inner(person):
        def whoSay(what):
            print(person(name)+"说了"+what)
        return whoSay
    return inner


@say("小明")
def who(name):
    return name

who("你好")

感觉和之前的不太一样对吧,因为之前的情况是被修饰的函数直接作为参数传递给修饰器,然后这种装饰器是带参数的,他的参数表其实就是在上面的小明,但是,who怎么作为参数传进去的呢?别着急,say调用完毕后,返回一个函数inner,这个才等价于之前那种情况,它会把who作为参数传进去,然后,它再返回whoSay,然后就是之前那种情况了,我们来看看,如果不用装饰器他是可以这样写的

#coding:utf-8
def say(name):
    def inner(person):
        def whoSay(what):
            print(person(name)+"说了"+what)
        return whoSay
    return inner

def who(name):
    return name

say("小明")(who)("你好")

更加猛烈一些吧

如果是多层装饰器又是什么情况
形如这样的


@sayAgain
@say
def who():
     return "小明"

笑嘻嘻(mmp),怎么写嘛

尝试下根据之前的规律,他一层的时候who的时候等价于say(who),此时的返回值是一个函数,如果嵌套,我猜测是sayAgain(say(who)),那么,最终sayAgain接受的参数是say返回的函数,然后,sayAgain自己再返回一个函数,如果是who("你好"),就成了,sayAgain(say(who))("你好")

然后我尝试下写

#输出小明说了你好,再见

#这里sayAgain接受的person实际是say的inner
def sayAgain(person):
    def inner():
        print(person()+",再见")
    return inner

#这里接受的person是who
def say(person):
    def inner():
        return person()+"说了你好"
    return inner


@sayAgain
@say
def who():
    return "小明"

who()
#所以这里的who其实等价于
#sayAgain(say(who))()

所总结出来的规律就是:多层嵌套的时候,上面的装饰器接受的参数,都是下面装饰器返回的函数(也就是被装饰过的函数),这样可以多层进行嵌套,感觉吊(M)吊(M)哒(P)


什么!还有更变态的?

如果每个装饰器都有参数,然后多层嵌套会是怎么样一种情况?我....擦,硬着来搞一下

根据之前带参数的装饰器的规律,装饰器的参数表已经知道了,然后它返回一个函数接受被修饰的函数作为参数,然后,再返回修饰后的函数,如果,多层也得遵循这个规律,我们看看这样的怎么写

@say("你好")
@person("小明")
def who(name):
  return name

宝宝硬要写
目标是输出:谁说了啥

#coding:utf-8

#这个修饰器主要是吧要说的内容加进去
def say(what):
    def inner(func):
        def personSay():
            print(func()+what)
        return personSay
    return inner

#这个修饰器主要是确定是谁在说
def person(name):
    def inner(func):
        def innerWhoSay():
            return func(name)+"说了"
        return innerWhoSay
    return inner


@say("你好")
@person("小明")
def who(name):
    return name
#被修饰的函数只是单纯的返回名字
#喵喵喵?这里居然who不带参数?那被修饰的函数参数哪里体现出来?其实在修饰器!
who()

那么其实等价于
say("你好")(person("小明")(who))()


大吉大利!

好比如说你有个小gun gun(98k),然后,你要给他加配件(修饰)让他功能更强大,然后,你先装上了枪托,然后再装个8倍镜,然后biubiubiu,下面用装饰器来尝试输出这样的结果

$ python3 98k.py 
98k已到手
已安装枪托配件
已安装8倍镜
目标命中!
$

代码如下

#coding:utf-8

#98k打一枪
#枪托
def stock(gun):
    def inner():
        gun()
        print("已安装枪托配件")
    return inner

#瞄准镜
def Sights(ratio):
    def inner(gun):
        def getSights():
            gun()
            print("已安装"+str(ratio)+"倍镜")
        return getSights
    return inner

#开枪
def shot(gun):
    def inner():
        gun()
        print("目标命中!")
    return inner


@shot
@Sights(8)
@stock
def gun():
    print("98k已到手")

#选用了4倍镜biubiubiu
gun()

上一篇 下一篇

猜你喜欢

热点阅读