码迷,mamicode.com
首页 > 编程语言 > 详细

Python之装饰器

时间:2019-01-23 11:38:05      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:tool   ima   user   from   font   调用   **kwargs   源代码   ret   

一. 什么是装饰器?

在说装饰器之前啊. 我们先说一个软件设计的原则: 开闭原则, 又被成为开放封闭原则,你的代码对功能的扩展是开放的你的程序对修改源代码是封闭的. 这样的软件设计思路可以更好的维护和开发。
  开放:对功能扩展开放
  封闭:对修改代码封闭

 

谈装饰器前,还要先要明白一件事,Python 中的函数可以像普通变量一样当做参数传递给另外一个函数,例如:

def foo():
    print("foo")

def bar(func):
    func()

bar(foo)

 

装饰器的目的: 在不改变原来代码的基础上. 给代码添加新功能。

 

二.  装饰器形成过程

01. 简单版装饰器:

def func1():
    print("欢迎访问主页")

# 添加一个登录验证的功能
def wrapper(fn):
    def inner():
        print("请先登录....")
        fn()  
    return inner

func1 = wrapper(func1)
func1()

# 装饰器的基本雏形
# def wrapper(fn): # fn:目标函数.
#     def inner():
#         ‘‘‘执行函数之前‘‘‘
#         fn() # 执行被装饰的函数
#         ‘‘‘执行函数之后‘‘‘
#     return inner

来看一下,执行流程:

技术分享图片

 

 02 . 语法糖

   但是如果有多个函数,都需要添加登录验证的功能,每次都得func1 = timer(func1)?这样还是有点麻烦,因为这些函数的函数名可能是不相同,有func1,func2,graph,等等,所以更简单的方法,python给你提供了,那就是语法糖。 @装饰器

def wrapper(fn):
    def inner():
        print("请先登录....")
        fn()
    return inner

@wrapper  # 相当于 => func1 = wrapper(func1)
def func1():
    print("欢迎访问主页")

func1()

有个小问题,就是查看func1函数名和函数注释都变成inner了。

print(func1.__doc__)     # 查看函数注释信息
print(func1.__name__)   # 查看函数名
# 我是内部函数
# inner

如何解决???
from functools import wraps
def wrapper(fn):
    @wraps(fn)   # 改变inner的名字
    def inner():
        """我是内部函数"""
        print("请先登录....")
        fn()
    return inner

@wrapper  # 相当于 => func1 = wrapper(func1)
def func1():
    """ 主页函数 """
    print("欢迎访问主页")

func1()

print(func1.__doc__)
print(func1.__name__)
#  主页函数 
# func1

 

 

03. 被装饰函数带参数和返回值

from functools import wraps
def wrapper(fn):  # fn: 目标函数, 被装饰的函数
    @wraps(fn)   # 改变inner的名字
    def inner(*args,**kwargs):  # 万能参数  *args, **kwargs: 接收参数
        """我是内部函数"""
        print("请先登录....")
        ret = fn(*args,**kwargs)      # 调用目标函数.
        """被装饰函数执行之后"""
        return ret                    # 返回结果
    return inner

@wrapper  # 相当于 => func1 = wrapper(func1)
def func1(usernamee):
    """ 主页函数 """
    print("欢迎 %s 访问主页" % usernamee)
    return True

@wrapper  # 相当于 => func2 = wrapper(func2)
def func2(name,age):
    print("名字:%s 年龄:%s" %(name,age))
    return True

ret = func1("lishichao")   # 实际执行的是inner 参数传给了inner函数
print(ret)

func2("lishichao","19")

 

04. 带有参数的装饰器

给装饰器传参,可以控制装饰器是否使用。

def wrapper(flag):  # 装饰器参数
    def inner1(fn):  # fn: 目标函数, 被装饰的函数
        def inner2(*args,**kwargs):  # 万能参数  *args, **kwargs: 接收参数
            """我是内部函数"""
            if flag:  # 判断传入的参数  True就执行装饰器 False不执行装饰器
                print("请先登录....")
            ret = fn(*args,**kwargs)      # 调用目标函数.
            """"""
            return ret                    # 返回结果
        return inner2
    return inner1

@wrapper(False) # 执行流程: 先执行wrapper(False)  返回装饰器 再和 @ 拼接起来 @inner1
def func1(usernamee):
    """ 主页函数 """
    print("欢迎 %s 访问主页" % usernamee)
    return True

ret = func1("lishichao")   # 实际执行的是inner 参数传给了inner函数
print(ret)

 

执行流程:

技术分享图片

 

 

05.多个装饰器装饰一个函数

def wrapper1(fn):
    def inner(*args, **kwargs):
        print("第一个装饰器开始")
        ret = fn(*args, **kwargs)
        print("第一个装饰器结束")
        return ret
    return inner

def wrapper2(fn):
    def inner(*args, **kwargs):
        print("第二个装饰器开始")
        ret = fn(*args, **kwargs)
        print("第二个装饰器结束")
        return ret
    return inner

def wrapper3(fn):
    def inner(*args, **kwargs):
        print("第三个装饰器开始")
        ret = fn(*args, **kwargs)
        print("第三个装饰器结束")
        return ret
    return inner

@wrapper1
@wrapper2
@wrapper3
def func():
    print("瞬间来三")

func()
# 执行结果
# 第一个装饰器开始
# 第二个装饰器开始
# 第三个装饰器开始
# 瞬间来三
# 第三个装饰器结束
# 第二个装饰器结束
# 第一个装饰器结束

 

执行流程:

wrapper1   
wrapper2   
wrapper3   # 调用函数执行之前
func
wrapper3   # 调用函数执行之后
wrapper2
wrapper1

技术分享图片

 

Python之装饰器

标签:tool   ima   user   from   font   调用   **kwargs   源代码   ret   

原文地址:https://www.cnblogs.com/root0/p/10307600.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!