Python装饰器

Python装饰器


python 是Python中比较难理解的概念。简单来说装饰器是用来对某个函数增加功能的,但又不需要改变函数提的内容。假设你们公司已经把一个项目开发了一段时间,但是发现前面写的某些方法需要添加一些功能(例如权限控制,打印日志等等)。最简单的方法就是直接去改这个方法就行了,但是你们已经在很多地方使用了这些方法,更改了这些方法后,就需要对这些调用的方法进行更改。这是一件十分麻烦的事情。弄不好整个系统就因此挂掉了。Python装饰器就能提供对方法就行扩展但又不需要改变原来方法的功能。以前对方法调用的方式也不用改变。比如以前有个方法funtionA(),那么以前没加装饰器前,你调用它用functionA(),加了装饰器后你依旧用functionA()调用即可。但是这时候调用就已经附加了一些功能。


示例:

def printMessage():
    print("--------欢迎您-------")

假设printMessage这个函数就是你原来的定义的函数,用来打印一行语句。那么你要调用这个函数的方式就是:

printMessage()
#输出为:--------欢迎您-------

现在你的这个函数已经被很多后续代码所使用,可能还有很多人也调用了你的代码。你被要求对这个printMessage函数进行扩展,但是你不能随意修改它(比如你想对函数加些参数,比如printMessage(name)),因为别人的代码引用了你的这个函数,你一改函数的调用形式,那么意味着别人也得改,那么后续的工作量就很大了。有没有什么办法不需要改函数的调用方式且能对printMessage添加一些功能呢?有!

def myDectoration(func):
    def inner():
        print("正在执行内部函数")
        func()
    return inner

def printMessage():
    print("--------欢迎您-------")
printMessage = myDectoration(printMessage)
printMessage()
#执行结果为:
正在执行内部函数
--------欢迎您-------

上面的函数myDectoration是Python中的闭包,从上面的代码我们可以看出我们调用printMessage()打印出来的信息比原来多了一行“正在执行内部函数”。功能多了但是调用方式便繁琐了,其他人还是得改变调用顺序,但是如果使用python的装饰器语法,调用方式就会与原来的调用方式如出一辙。

def myDectoration(func):
    def inner():
        print("正在执行内部函数")
        func()
    return inner

@myDectoration
def printMessage():
    print("--------欢迎您-------")

printMessage()

上面printMessage函数上面的@myDectoration就是装饰器的语法,它用myDectoration函数来装饰printMessage函数。这里的@myDectoration放在printMessage上面相当于执行:

printMessage = myDectoration(printMessage)

那么这句执行 myDectoration方法时,printMessage指向的地址传递给func,然后myDectoration内部是定义了一个inner函数所以并不执行,但是最后一句会返回inner函数的地址。此时将返回值赋值为printMessage,那么printMessage指向的地址就是inner函数的地址,当我们调用printMessage()时,inner函数被执行,先打印“正在执行内部函数”,然后条用func(),此刻的func是指向我们要装饰的函数的地址的。这样就打印了”——–欢迎您——-“。

def myDectoration(func):
    print("执行myDectoation函数")
    def inner():
        print("正在执行内部函数")
        func()
    return inner

@myDectoration
def printMessage():
    print("--------欢迎您-------")

上面代码的输出结果为:

执行myDectoation函数

我们并没有调用任何函数为何myDectoration会被执行。这就是装饰器的独特效果。当我们在一个函数先使用@myDectoration对一个函数进行装饰的时候,其实就已经执行了“printMessage = myDectoration(printMessage)”,所以会执行打印”执行myDectoation函数”的效果。


当被装饰函数需要传递参数时的用法:

def myDectoration(func):
    print("执行myDectoation函数")
    def inner(*args):
        print("正在执行内部函数")
        func(*args)
    return inner



@myDectoration
def printMessage(name):
    print("--------%s欢迎您-------"%name)

printMessage("Bob")

我们前面说过我们最后一行调用printMessage(“Bob”)时候,printMessage已经不指向原始的函数了而是指向inner函数的地址,那么我们最后这句printMessage(“Bob”)其实对应执行的是inner函数块里面的内容。
输出结果为:

执行myDectoation函数
正在执行内部函数
--------Bob欢迎您-------

当有多个装饰器时候的执行次序:

def myDectoration1(func1):
    print("执行myDectoation函数1")
    def inner1(*args):
        print("正在执行内部函数1")
        return func1(*args)+"中国欢迎你"
    return inner1

def myDectoration2(func2):
    print("执行myDectoation函数2")
    def inner2(*args):
        print("正在执行内部函数2")
        return "英俊帅气的"+func2(*args)
    return inner2


@myDectoration1
@myDectoration2
def printMessage(name):
    return "%s欢迎您"%name

messgae = printMessage("Bob")
print(messgae)

输出结果为:

执行myDectoation函数2
执行myDectoation函数1
正在执行内部函数1
正在执行内部函数2
英俊帅气的Bob欢迎您中国欢迎你

看下上面的代码,我们用了两个装饰器myDectoration1,myDectoration2来装饰printMessage函数,想想为何输出结果这那样的。@myDectoration1需要装饰一个函数,但是它发现下面并不是一个函数,下面是还有一个装饰器@myDectoration2,那么@myDectoration1要做的就是等@myDectoration2先对printMessage这个函数装饰返回一个函数,然后@myDectoration1对这个函数再进行装饰。那么再捋一捋程序的执行流程:

#执行流程:
printMessage = myDectoration2(printMessage)
#func2指向printMessage,执行时首先打印出“执行myDectoation函数2”,接着向下执行,
# 发现定义了一个函数,跳过,返回inner2的地址
#此刻printMessage指向inner2函数的地址,接下来轮到@myDectoration1装饰了
printMessage = myDectoration2(printMessage)
#func1指向printMessage,即指向inner2,执行时首先打印出“执行myDectoation函数1”,接着向下执行,
# 发现定义了一个函数inner1,跳过,返回inner1的地址
#此刻printMessage指向inner1函数的地址。
messgae = printMessage("Bob")
#那么当我们执行messgae = printMessage("Bob")时候,首先调用inner1(*args)。
#打印“正在执行内部函数1”,接着执行内部的func1(*args)函数,此刻func1
#指向的是inner2,即执行inner2(*args),打印出
#"正在执行内部函数2"
#然后调用func2(*args)
#打印出“Bob欢迎您”
#将其返回到"英俊帅气的"+func2(*args)这一句
#然后将“英俊帅气的Bob欢迎你”返回到
#func1(*args)+"中国欢迎你"
#拼接后的“英俊帅气的Bob欢迎您中国欢迎你”作为
#printMessage返回值赋给message变量

带参数的装饰器:

def func(message):
    print("%s"%message)
    def myDectoration(func):
        print("执行myDectoation函数2")
        def inner(*args):
            print("正在执行内部函数2")
            func(*args)
        return inner
    return myDectoration

@func("welcome")
def test():
    print("hello world")

test()

执行结果过下:

welcome
执行myDectoation函数2
正在执行内部函数2
hello world

@func(“welcome”)相当于先执行了func(welcome)函数然后用返回的myDectoration和@组成@myDectoration来装饰test函数。


类装饰器:
其实是可以用一个类来装饰一个函数的。

class Test():
    def __init__(self,func):
        self.__func =func
    def __call__(self):
        print("我可以进行装饰")
        self.__func()
@Test
def test():
    print("hello world")

test()

上面用类来装饰test函数时,相当于执行了test = Test(test)操作。首先会创建一个Test类的对象,其中”self.__func”指向test函数,一旦一个类中有“__call__”方法那么这个类生成的对象就是可以通过”对象名()”这样的方式进行调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值