【菜鸟零基础学习笔记】Day20-装饰器

【装饰器】

本节资料来源:

装饰器

 

什么是装饰器?

器即函数

装饰即修饰,意指为其他函数添加新功能

装饰器定义:本质就是函数,功能是为其他函数添加新功能

 

装饰器需要遵循的原则

1.不修改被装饰函数的源代码(开放封闭原则)

2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式

 

实现装饰器知识储备

装饰器=高阶函数+函数嵌套+闭包

高阶函数

高阶函数定义:
1.函数接收的参数是一个函数名

2.函数的返回值是一个函数名

3.满足上述条件任意一个,都可称之为高阶函数

 

举例一:

--函数的参数是一个函数名--

实现在不修改源代码的情况下为foo函数添加功能,但是改变了foo函数的调用方式:

(原先调用foo函数是用foo()这种方法,但是添加了“计算时间”的新功能之后,调用方式变成"test(foo)")

import time
def foo():     #这不是一个高阶函数
    time.sleep(3)
    print("你好啊林师傅")

def test(func):  #这是一个高阶函数(形参接受的值是一个函数名)
    print(func)   #<function foo at 0x000001A7E80A36A8>打印了函数foo的内存地址
    start_time = time.time()
    func()      #你好啊林师傅
    stop_time = time.time()
    print('函数运行时间是 %s' %(stop_time - start_time))   #函数运行时间是 3.000262498855591
test(foo)

 

举例二:

--函数的返回值是一个函数名--

实现“不改变函数的调用方式”

def foo():
    print('from the foo')
def test(func):
    return func
foo = test(foo)
foo()   #from the foo

启发:将上述两者结合就能既在不修改原代码的情况下添加新功能,又不改变函数的调用方式

 

举例三:既在不修改原代码的情况下添加新功能,又不改变函数的调用方式

import time
def foo():
    time.sleep(3)
    print('from the foo')
def timer(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print('函数运行时间是 %s' % (stop_time - start_time))
    return func  #拿到func函数的运行地址
foo = timer(foo)   #把func函数的地址赋值给foo
foo()


输出:
from the foo
函数运行时间是 3.0008068084716797
from the foo

但是,举例三多运行了一步,不合格

结论:高阶函数解决不了这个问题

 

函数嵌套

什么是函数的嵌套?

#在一个函数内部调用另外一个函数,不叫函数的嵌套
def bar():
    print('from bar')

def foo():
    print('from foo')
    bar()
#在一个函数内部定义另一个函数,叫做函数的嵌套
def bar():
    print('from bar')

def foo():
    print('from foo')
    def test():
        pass

举例一:一个函数嵌套的例子

def father(name):
    print('from father %s' %name)
    def son():
        print('from son')
        def grandson():
            print('from grandson')
        grandson()
    son()

father('林海峰')

输出:
from father 林海峰
from son
from grandson

举例二:函数也是一个变量

def father(name):
    print('from father %s' %name)
    def son():   #函数也是一个变量
        print('from son')
    print(locals())   #打印当前层的局部变量
father('alex')

输出:
from father alex
{'son': <function father.<locals>.son at 0x00000244C4963620>, 'name': 'alex'}

注意:
这个例子中的son是局部变量,只能在局部调用

举例三:函数嵌套要注意作用域

def father(name):
    #print('from father %s' %name)
    def son():
        print('我的爸爸是%s' %name)   #当前层级没有name变量,所以去上一级找
        def grandson():
            name = 'alex'
            print('我的爷爷是%s' %name)
        grandson()   #当前层级有name变量,所以用alex
    #print(locals())
    son()
father('linhaifeng')


输出:
我的爸爸是linhaifeng
我的爷爷是alex

闭包

什么是闭包?闭包就是之前讲过的作用域的一种体现

最外层的变量可以传入最里层

 

装饰器实现

import time
#装饰器的架子
def timmer(func):  #func = test
    def wrapper():
        #print(func)
        start_time = time.time()
        func()   #当前层级没有变量func,所以往上一层找。这一句就是在运行test()
        stop_time = time.time()
        print('运行时间为 %s' %(stop_time-start_time))
    return wrapper  #return的是嵌套在函数里的那个函数

@timmer
def test():   #test是被修饰函数
    time.sleep(3)
    print('test函数运行完毕')

#下面两行是改变了函数调用方式的情况
# res = timmer(test) #返回的是wrapper的地址
# res()  #运行wrapper函数

#下面两行是没有改变函数调用方式的情况
# test = timmer(test) #返回的是wrapper的地址
# test()  #运行wrapper函数

#这是一个更方便的方法:在被修饰函数之前加上@timmer
#@timmer就相当于 test = timmer(test)
#在被修饰的函数开投行加上@timmer

注意:要理解装饰器运行时每一句语句的运行顺序!!(视频:Day20-10)

加上被修饰的函数的返回值

返回值的例子一:

import time
#装饰器的架子
def timmer(func):  #func = test
    def wrapper():
        start_time = time.time()
        func()   #当前层级没有变量func,所以往上一层找。这一句就是在运行test()
        stop_time = time.time()
        print('运行时间为 %s' %(stop_time-start_time))
        return '123'
    return wrapper

@timmer   #test = timmer(test)
def test():   #test是被修饰函数
    time.sleep(3)
    print('test函数运行完毕')
    return '这是test的返回值'

res = test()   #实际上运行的是timmer的返回值wrapper
print(res)   #123

返回值的例子二:

import time
#装饰器的架子
def timmer(func):  #func = test
    def wrapper():
        start_time = time.time()
        res = func()
        stop_time = time.time()
        print('运行时间为 %s' %(stop_time-start_time))
        return res
    return wrapper

@timmer   #test = timmer(test)
def test():   #test是被修饰函数
    time.sleep(3)
    print('test函数运行完毕')
    return '这是test的返回值'

res = test()   #实际上运行的是timmer的返回值wrapper
print(res)   #这是test的返回值

 

加上参数

import time
#装饰器的架子
def timmer(func):  #func = test
    def wrapper(*args,**kwargs):   #可变长传值。因为被修饰的函数的参数是不固定的,所以不能写死
        start_time = time.time()
        res = func(*args,**kwargs)  #可变长传值
        stop_time = time.time()
        print('运行时间为 %s' %(stop_time-start_time))
        return res
    return wrapper

@timmer   #test = timmer(test)
def test(name,age):   #test是被修饰函数
    time.sleep(3)
    print('test函数运行完毕,名字是【%s】 年龄是【%s】' %(name,age))
    return '这是test的返回值'

@timmer   #test = timmer(test)
def test1(name,age,gender):   #test是被修饰函数
    time.sleep(3)
    print('test函数运行完毕,名字是【%s】 年龄是【%s】 性别是【%s】' %(name,age,gender))
    return '这是test的返回值'

test('linhaifeng',18)   #实际上运行的是timmer的返回值wrapper
test1('linhaifeng',18,'male')

当运行

test('linhaifeng',18)

的时候,对于

def wrapper(*args,**kwargs):

这句语句,*args接收的是('linhaifeng')这个元组;*kwargs接收的是{'age':18} 这个字典,所以

 res = func(*args,**kwargs)

相当于

func(*('linhaifeng'),**{'age':18})

其实就是原封不动地往下传值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值