美文网首页
python装饰器

python装饰器

作者: 裂开的汤圆 | 来源:发表于2019-06-10 14:09 被阅读0次

首先让我们来了解一下装饰器的作用

软件开发中最重要的一条真理就是“不要重复自己的工作”,当我们已经写好了一个函数,并且也在其他地方调用了这个函数,那我们如何在不修改原函数的代码,也不修改其他调用这个函数的代码的条件下去拓展原函数的功能呢?
装饰器就可以解决这个问题,解决的方法也很简单,给原函数加上一个包装层,具体的思路就是,写一个装饰器函数,这个函数的作用就是包装原函数,并返回包装后的新函数。
<font color='red'>总结来说装饰器就是一个函数,它可以接受一个函数作为输入并返回一个新的函数作为输出(这里是重点,记笔记)。</font>

在学习装饰器之前,我们先了解两个概念

1.python的函数都是对象,让我们看两个例子

def hello():
    print 'hello world'

hello()    # hello world

# 函数也是一个对象,可以将它赋值给任何变量
# 这里需要注意的是,该语句并没有执行函数,只不过将函数赋值给了一个变量
study = hello

# 下面这句才是调用函数
study()    # hello world

# 将hello删除,在调用study(),会是怎样的结果?
del hello    # NameError: name 'hello' is not defined
study()    # hello world

上面的例子,除了调用函数之外,其他的部分的操作和变量是一模一样的。

2.既然python中的函数是对象,那么以下对对象执行的操作,函数也可以完成:

  • 赋值给变量
  • 在对象中定义一个内部对象

让我们看例子

def hello():
    def nei():
        return 'hello wordl'
    return nei

# 我们调用hello函数,看看返回的是什么
a = hello()
type(a)    # function
# 可以看到,返回的是一个function对象
# 如果我要执行该函数呢?没错和上面那个例子一样,在参数后加上括号
a()    # hello world

# 如果我们想直接返回该函数的调用结果又该怎样去修改上面的函数呢?
def hello():
    def nei():
        return 'hello wordl'
    # 直接加上括号,表示调用该函数
    return nei()

hello()    # hello world

实现一个装饰器

直接看例子

# 原函数
def login():
    print '执行原函数'

# 装饰器函数,传入原函数,返回包装后的新函数
def zsq(func):
    def nei():
        print '传入函数前的操作'
        func()   #执行原函数
        print '传入函数后的操作'
    return nei

#  将原函传入装饰器,覆盖原函数入口
>>> login = zsq(login)

# 调用被装饰后的函数
>>> login()
传入函数前的操作
执行原函数
传入函数后的操作

再让我们来看看python的装饰器是如何编写的,虽然代码不尽相同,不过实现的功能是一样的。

from functools import wraps

# 装饰器函数
def zsq(func):    
    @wraps(func)         # 这个用于保存原函数的元数据,下一节会针对这个详细讲解
    def nei():
        print '传入函数前的操作'
        func()   #调用原函数 
        print '传入函数后的操作'
    return nei

# 原函数
@zsq              # 这句话等价于:login = zsq(login),覆盖了原函数的入口
def login():
    print '原函数功能'

>>> login()
传入函数前的操作
原函数功能
传入函数后的操作

编写装饰器时保存函数的元数据

我们编写好了一个装饰器,但是当将它用在一个函数上时,一些重要的元数据,比如函数名、文档字符串、函数注解以及调用签名都丢失了。
那我们如何在编写装饰器时如何保存函数的元数据呢?,解决方案就是为包装函数添加functools库中的@wraps装饰器。
我们先来看看不添加@warps的效果

# 装饰器函数
def zsq(func):    

    def nei(*args, **kwargs):
        print '传入函数前的操作'
        func()
        print '传入函数后的操作'
    return nei

# 原函数
@zsq              # 这句话等价于:login = zsq(login),覆盖了原函数的入口
def login():
    '''
    原函数注解
    '''
    print '原函数功能'


>>>login.__name__
'nei'

>>>login.__doc__

可以看到,原函数的注解和函数名都已经丢失,加上@wraps就可以防止这种情况的出现,保存原函数的元数据。
再让我们看看加了@wraps(func)的效果

# 装饰器函数
def zsq(func):    
    @wraps(func)    # 保存原函数的元数据
    def nei():
        print '传入函数前的操作'
        func()
        print '传入函数后的操作'
    return nei

# 原函数
@zsq              # 这句话等价于:login = zsq(login),覆盖了原函数的入口
def login():
    '''
    原函数注解
    '''
    print '原函数功能'


>>> login.__name__
'login'

>>> print login.__doc__
原函数注解

参考文章

Python装饰器:简单装饰,带参数装饰与类装饰器
Python中如何在一个函数中加入多个装饰器?

相关文章

  • 装饰器模式

    介绍 在python装饰器学习 这篇文章中,介绍了python 中的装饰器,python内置了对装饰器的支持。面向...

  • python中的装饰器

    python装饰器详解 Python装饰器学习(九步入门) 装饰器(decorator) 就是一个包装机(wrap...

  • [译] Python装饰器Part II:装饰器参数

    这是Python装饰器讲解的第二部分,上一篇:Python装饰器Part I:装饰器简介 回顾:不带参数的装饰器 ...

  • Python中的装饰器

    Python中的装饰器 不带参数的装饰器 带参数的装饰器 类装饰器 functools.wraps 使用装饰器极大...

  • Python进阶——面向对象

    1. Python中的@property   @property是python自带的装饰器,装饰器(decorat...

  • Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方

    Python 装饰器简介装饰器(Decorator)是 Python 非常实用的一个语法糖功能。装饰器本质是一种返...

  • Python装饰器

    Python装饰器 一、函数装饰器 1.无参装饰器 示例:日志记录装饰器 2.带参装饰器 示例: 二、类装饰器 示例:

  • python3基础---详解装饰器

    1、装饰器原理 2、装饰器语法 3、装饰器执行的时间 装饰器在Python解释器执行的时候,就会进行自动装饰,并不...

  • 2019-05-26python装饰器到底是什么?

    装饰器例子 参考语法 装饰器是什么?个人理解,装饰器,是python中一种写法的定义。他仍然符合python的基本...

  • 2018-07-18

    Python装饰器 装饰,顾名思义,是用来打扮什么东西的。Python装饰...

网友评论

      本文标题:python装饰器

      本文链接:https://www.haomeiwen.com/subject/kviltctx.html