原来这就是python装饰器

        我们利用一个生活中的场景来进入装饰器的世界!

        我们模拟银行存取款的过程,代码如下:

def deposit():
    print('存款中...')

def withdraw():
    print('取款中...')

key = 1
if key == 1:
    deposit()
else:
    withdraw()

          好像还不完美,我们存取款的时候必需要输入密码的,于是成了下面的样子。

def deposit():
    print('存款中...')

def withdraw():
    print('取款中...')

def check_password():
    print('密码验证中...')

key = 1
if key == 1:
    check_password()
    deposit()
else:
    check_password()
    withdraw()

       这个样子好像也不成,在if...else中每次判断都需要加上密码的验证函数,当我们的代码很多的时候,那得加得多累啊。

        还有一种将check_password()函数分别放在存取款函数中,在代码量增加的时候,还是和这个一样的效果。我们的目标是尽量少些代码,是代码模块话,于是有了下面的版本。

def deposit():
    print('存款中...')

def withdraw():
    print('取款中...')

def check_password(func):
    print('密码验证中...')
    func()

key = 1
if key == 1:
    check_password(deposit)
else:
    check_password(withdraw)

       虽然上面的代码量减少,看起来更加的完美,但是如果业务逻辑代码增加的话,我们是不是得改得天荒地老。我们需要一个方法,只要改变check_password()函数,不需要更改其他。

def deposit():
    print('存款中...')

def withdraw():
    print('取款中...')

def check_password(func):
    def inner():
        print('密码验证中...')
        func()
    return inner

deposit = check_password(deposit)
withdraw = check_password(withdraw)
key = 1
if key == 1:
    deposit()
else:
    withdraw()

       当改为上面这个样子后,是不是发现我们的代码结构好了很多!这个就是装饰器的强大之处。上面的check_password()函数就是闭包了。所谓闭包就是在函数中嵌套了另一个函数,该内部函数被当作对象返回是,并且内部函数引用了外部变量,此时就形成了闭包。check_password()就是deposit()withdraw()的装饰器函数。

        当函数不加括号,是不会被执行的,它代表的是一个函数对象,可以当作变量来传递。可以通过打印看到其返回的是一个地址。

        我们利用存款函数再来分析一下调用过程!我们看到deposit 实际上就是check_password(deposit),而deposit作为参数传递给check_password,check_password的子函数inner对func返回的结果进行了一番修饰,(即加上了“密码验证中...”这句打印)返回一个装饰后的结果,最后check_password返回inner,可以说inner就是装饰后的deposit,这个就是一个函数被装饰的过程,这就是我们把check_password叫做装饰函数的原因,因为其内部对deposit进行了装饰。

        python中我们还能利用语法糖,让代码更加的简洁。

def check_password(func):
    def inner():
        print('密码验证中...')
        func()
    return inner

@check_password
def deposit():
    print('存款中...')

@check_password
def withdraw():
    print('取款中...')

key = 1
if key == 1:
    deposit()
else:
    withdraw()

       来一段比较官方的定义,“装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。”

装饰器装饰有参函数

def celebrator(func):
    def inner(str):
        print('我是新增功能')
        func(str)
    return inner

@celebrator
def myprint(a):
    print(a)
#myprint = celebrator(myprint)
myprint('hello python!')
#output:
#我是新增功能
#hello python!

        当我们被装饰的函数有参数的时候,我们的装饰器函数的inner函数也需要有参数,这样才能将被装饰的函数传入装饰器;这里我觉得可以简单的理解为我们可以把被装饰函数等同为inner函数。

       我们被装饰函数的参数可能有很多,而我们的装饰器只有这一个,为了增加装饰器函数的通用型,我们需要进一步优化代码。

def celebrator(func):
    def inner(*args,**kargs):
        print('我是新增功能')
        func(*args,**kargs)
    return inner

@celebrator
def myprint(a):
    print(a)

#myprint = celebrator(myprint)
myprint('hello python!')

          当被装饰的函数有返回值的时候,我们在装饰器函数中也需要将被装饰的函数返回。

def celebrator(func):
    def inner(*args,**kargs):
        print('我是新增功能')
        ret = func(*args,**kargs)
        return ret
    return inner

@celebrator
def myprint(a):
    print(a)

@celebrator
def myprint1(b):
    return b

ret1 = myprint("aaaaaaa")
ret2 = myprint1("bbbbbb")
print(ret1,ret2)

#output:
#我是新增功能
#aaaaaaa
#我是新增功能
#aaaaaaa bbbbbb

        可以看到有返回值的被装饰后依然有返回值,没有返回值的函数被装饰后依然没返回值,符合我们的预期。

双重语法糖

def printequal(func):
    def inner():
        print('='*15)
        func()
    return inner

def printstar(func):
    def inner():
        print('*'*15)
        func()
    return inner

@printequal
@printstar
def myprint():
    print('hello python')

myprint()
#output:
#===============
#***************
#hello python

          显然,上面这个函数还是有很大的改进空间的,明显两个打印函数都有很多重合的地方,于是,我们得到了以下的实现。

def get_celebrator(char):
    def print_style(func):
        def inner():
            print(char*15)
            func()
        return inner
    return print_style

@get_celebrator('=')
@get_celebrator('*')
def myprint():
    print('hello python')

myprint()

https://blog.csdn.net/qq_42156420/article/details/81169554

你可能感兴趣的:(Python)