如何理解python装饰器

闭包

 

 

装饰器(decorator)

def yanzheng(func):
    def inner():
        print("正在验证1 2 3")
        func()
        print("执行完成")
    return inner
# 使用装饰器的形式 @装饰器函数
@yanzheng
def f1():
    print("in f1")
"""上面三行的代码等价于
def f1():
    print("这是一个底层的函数")
f1 = yanzheng(f1)
"""
# f1已经不是原来的f1了 而是一个被装饰之后的f1
f1()
@yanzheng
def f2():
    print("in f2")
f2()

"""装饰器函数的特点 符合闭包的基本形式 有一个函数参数是被装饰的函数的引用"""

 

有参数和有范围值的装饰器

import time


def gettime(func):
    def inner(*args, **kwargs):  # 将收到数据的打包  位置参数和关键字参数
        begin = time.time()
        # 将被装饰的函数返回值暂存
        ret = func(*args, **kwargs)  # 将收到的参数拆包为收到的样子
        end = time.time()
        print("函数花费%f" % (end-begin))
        return ret
    return inner

@gettime
def f1():
    print("in f1")
    for i in range(1):
        time.sleep(1)


@gettime
def f2(number2):  # f2 = gettime(f2)
    print("number2 = %d" % number2)
    time.sleep(0.2)
    print("in f2")
    return 100

f1()
print("函数的返回值是%s" % f2(100))

 

装饰器工厂

import time

# 产生装饰器函数的函数就是装饰器工厂
# 目的:通过给装饰器工厂函数传递参数 控制内部函数的行为
def get_run_time(flag):
    def gettime(func):
        def inner(*args, **kwargs):  # 将收到数据的打包
            begin = time.time()
            # 将被装饰的函数返回值暂存
            ret = func(*args, **kwargs)  # 将收到的参数拆包为收到的样子
            end = time.time()
            if flag == 'int':
                print("函数花费%d s" % int(end - begin))
            else:
                print("函数花费%f s" % (end-begin))
            return ret
        return inner
    return gettime

@get_run_time("int")
def f1():
    print("in f1")
    for i in range(1):
        time.sleep(1)
f1()

 

 

类装饰器

装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重写了 __call__() 方法,那么这个对象就是callable的。

class Test(object):
    def __init__(self, func):
        print("---初始化---")
        print("func name is %s"%func.__name__)
        self.__func = func
    def __call__(self):
        print("---装饰器中的功能---")
        self.__func()
#说明:
#1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
#   并且会把test这个函数名当做参数传递到__init__方法中
#   即在__init__方法中的属性__func指向了test指向的函数
#
#2. test指向了用Test创建出来的实例对象
#
#3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
#
#4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用
#   所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体
@Test
def test():
    print("----test---")
test()
showpy()#如果把这句话注释,重新运行程序,依然会看到"--初始化--"

运行结果如下:

---初始化---
func name is test
---装饰器中的功能---
----test---

 

多重装饰器

def makeBold(fn):
    def wrapped():
        return "<b>" + fn() + "</b>"
    return wrapped


def makeItalic(fn):
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

# f1 = makeBold(f1)
@makeBold
@makeItalic
def f1():
    return "hello"

@makeItalic
@makeBold
def f2():  #先靠近f2的装饰器先执行
    return "python"

print(f1())
print(f2())

运行结果:

<b><i>hello</i></b>
<i><b>python</b></i>

 

posted @ 2019-09-02 22:44  snailon  阅读(404)  评论(0)    收藏  举报