Python基础 —— 装饰器函数

装饰器函数

导航

装饰器的形成过程

装饰器的主要功能和固定结构

带参数的装饰器

多个装饰器装饰同一个函数

 

装饰器的形成过程

装饰器的功能了解

import time

def func1():
    print("in func1")

def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time()-start)
    return inner

func1 = timer(func1)
func1()


'''
timer(func1)() --> 即执行的是 inner()

输出:
in func1
0.0
'''
装饰器 - 简单版

需要在目标的执行函数上加一次赋值调用。

装饰器的语法糖

def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)

    return inner


@timer
def func1():    # ==> func1 = timer(func1)
    print("in func1")


func1()
装饰器 - 语法糖

总结

  • 装饰器的本质:一个闭包函数
  • 装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展

 

装饰一个带参数的函数

def timer(func):
    def inner(a):    ###
        start = time.time()
        func(a)        ###
        print(time.time() - start)

    return inner


@timer
def func1(a):       ###
    print("in func1 " + a)


func1("hello world")
被装饰函数需要传参

 

不同函数需要不同的参数,但又需要同一个功能的装饰器。

ef timer(func):
    def inner(*args, **kwargs):
        print("函数开始执行")
        func(*args, **kwargs)
        print("函数执行结束")

    return inner


@timer
def func1(name):
    print("..." + name)


@timer
def func2(age):
    print("年龄:",age)


func1("Clare")
func2(18)


'''
函数开始执行
...Clare
函数执行结束
函数开始执行
年龄: 18
函数执行结束
'''
一次性hold住所有函数传参

 

带返回值的装饰器

def timer(func):
    def inner(*args, **kwargs):
        ret = func(*args, **kwargs)
        return ret    ###

    return inner


@timer
def func1(name):
    return "姓名:%s" % name


res = func1("Clare")
print(res)

'''
姓名:Clare
'''
被装饰函数有返回值

 

查看函数信息的方法失效及问题解决

def timer(func):
    def inner(*args, **kwargs):
        ret = func(*args, **kwargs)
        return ret

    return inner


@timer
def func1():
    '''这是一个func1'''
    return "in func1"


print(func1.__doc__)  # 查看函数注释:None
print(func1.__name__)  # inner,执行func1实际是执行:timer(func1)(),即inner()


#############  对比  #############
def func2():
    '''这是一个func1'''
    return "in func1"


print(func2.__doc__)  # 查看函数注释:"这是一个func1"
print(func2.__name__)  # func2
查看函数信息的方法失效
from functools import wraps


def timer(func):
    @wraps(func)
    def inner(*args, **kwargs):
        ret = func(*args, **kwargs)
        return ret

    return inner


@timer
def func1():
    '''这是一个func1'''
    return "in func1"


print(func1.__doc__)  # 这是一个func1
print(func1.__name__)  # func1
解决方法:@wraps(func)

 

 

装饰器的主要功能和固定结构

装饰器的主要功能

在不改变函数调用方式的基础上在函数的前、后添加功能。

装饰器的固定结构

def wrapper(func):
    def inner(*args, **kwargs):
        '''执行函数之前要进行的操作'''
        ret = func(*args, **kwargs)
        '''执行函数之后要进行的操作'''
        return ret
    return inner
from functools import wraps

def wrapper(func):
    @wraps(func)    # 最内层函数上方
    def inner(*args, **kwargs):
        ret = func(*args, **kwargs)
        return ret

    return inner
wraps(func) 固定结构

 

带参数的装饰器

  • 如果说很多个函数共同使用了一个装饰器,现需要取消掉装饰器的功能。万一去掉之后又需要加上,工作量太过繁重。
  • 或者说某几个函数仍需要该装饰器,而另外几个函数暂时性的不需要呢。
def outer(flag):
    def wrapper(func):
        def inner(*args, **kwargs):
            if flag:
                print('''执行函数之前要进行的操作''')
            ret = func(*args, **kwargs)
            if flag:
                print('''执行函数之后要进行的操作''')
            return ret

        return inner

    return wrapper


############## 不需要被装饰 ########### 
@outer(False)
def func():
    print("in func")

func()  # in func


############## 需要被装饰  ###########
@outer(True)
def func():
    print("in func")

func()

'''
执行函数之前要进行的操作
in func
执行函数之后要进行的操作
'''
控制函数是否需要被装饰

 

多个装饰器装饰同一个函数

def wrapper1(func):
    def inner(*args, **kwargs):
        print("wrapper1")
        ret = func(*args, **kwargs)
        print("wrapper1")
        return ret

    return inner


def wrapper2(func):
    def inner(*args, **kwargs):
        print("wrapper2")
        ret = func(*args, **kwargs)
        print("wrapper2")
        return ret

    return inner


@wrapper2      # func1 = wrapper2(wrapper1(func))
@wrapper1      # func1 = wrapper1(func)
def func():
    print("func")

func()


'''
wrapper2
wrapper1
func
wrapper1
wrapper2
'''
多个装饰器装饰同一个函数的执行顺序
一个装饰器时可以简写为
return func(*args, **kwargs)

多个装饰器时,不能简写,不会执行return后的代码
ret = func(*args, **kwargs)
return ret
注意

 

 

 

 

 

 

 

 

 

 

 

#####################################

一、解耦

  要完成一个完整的功能,但这个功能的规模要尽可能小,并且和这个功能无关的其他代码应该和这个函数分离

    # 1、增强代码的可读性

    # 2、减少代码变更的重复影响

1 def func():
2     while True:
3         print("从前有座山,山里有座庙,庙里有个老和尚在讲故事,故事是这样的:")
4     
5 func()
# 运行结果:会无休止的打印该字符串,没有结束。
1 def func():
2     print("从前有座山,山里有座庙,庙里有个老和尚在讲故事,故事是这样的:")
3    
4 for i in range(10):
5     func()
# 打印该字符串十次。修改range里的数值可控制打印次数。 

二、递归

什么是递归:

  # 1、一个函数在自己内部调用自己。

  # 2、递归的层数在python里是有限制的。(997/998层)

posted @ 2020-10-12 10:22  乖巧Clare  阅读(124)  评论(0编辑  收藏  举报