python学习笔记3.4-函数装饰器

软件开发的过程中,最基本的技能就是:不要重复自己的工作。也就是说,在任何时候,当需要创建高度重复的代码时,通常都需要寻找一个更加快捷的解决方案。在python中,这类问题常常会归为“元编程”。 简而言之,元编程的主要目标是创建函数和类,并用他们来操纵代码(通常的行为有生成、修改、包装已有的代码)。Python中基于这个目的的方法有装饰器、类装饰器、元类以及有用的主题(常见的有对象签名、用exec()来执行代码以及检查函数和类的内部结构)。 元编程系列主要内容是探讨各种元编程技术,通过实例来讲解如何利用这些技术来自定义python的行为,使其能满足我们不同寻常的需求。

1 装饰器

1.1 用装饰器给函数添加一个包装

装饰器的本质就是一个函数,它可以接受一个函数作为输入并返回一个新的函数作为输出。我们可以利用给函数来建立一个装饰器(相当于给函数加上包装层)来添加额外的处理,例如记录日志、计时统计等。 最简单的一个例子是计时系统,我想记录函数的运行时间并打印到控制台,最通常的做法是:

def CutDown(n):
    import time
    start = time.time()

    while n > 0:
        n -= 1

    end = time.time()

    print(end-start)

CutDown(10000000)
屏幕输出:1.1250569820404053

下面引入装饰器方法:

def GetRunTime(func):
    import time
    from functools import wraps

    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(func.__name__, end - start)
        return result

    return wrapper


@GetRunTime
def cutdown(n):
    while n > 0:
        n -= 1

cutdown(10000000)
屏幕输出:cutdown 1.1274616718292236

用第二种方法的好处就是,加入我需要在很多的函数上记录其运行时间,则只需要在需要记录时间的函数上面添加@GetRunTime即可,调试非常方便,代码也简洁易懂。

装饰器内部的代码一般会涉及创建一个新的函数,利用*args和**kwargs来接受任意的参数,在示例中wrapper()函数就是这么操作的。在这个函数的内部,我们需要调用原来的输入参数(即被包装的函数的输入参数)并返回它的结果。

其实运行过程就是将被装饰函数打包到装饰器中运行并返回运行结果,作为代价肯定是需要牺牲一定的效率的。在示例中还有一个是需要注意的,那就是@wraps(func),它用来保存函数的元数据。其实也可以不要这个,但是就会丢失被装饰函数的一些元数据,例如函数名、文档字符串、函数注解以及调用签名。1.2就会讲解如何保存元数据。

1.2 运用装饰器时保存函数的元数据

在1.1中也提到过,即使没有@wraps(func)函数也能运行,代价是丢失一些函数的元数据:

def GetRunTime(func):
    import time
    #from functools import wraps

   # @wraps(func)
    def wrapper(*args, **kwargs):
        """
        :param args:
        :param kwargs:
        :return:
        """
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(func.__name__, end - start)
        return result

    return wrapper


@GetRunTime
def cutdown(n):
    """
    :param n:
    :return:
    """
    while n > 0:
        n -= 1

cutdown(10000000)
print(cutdown.__name__)
print(cutdown.__doc__)

控制台打印信息:

cutdown 1.4844520092010498
wrapper

        :param args:
        :param kwargs:
        :return:

我们发现打印信息不是cundown这个函数的,而是装饰器函数的。再使用@wraps(func)这个技术: (代码略) 控制台打印信息:

cutdown 1.193265676498413
cutdown

    :param n:
:return:

这个时候所有信息都属于cutdown函数的。 上面这个例子告诉我们,在我们自己编写装饰器的时候一定要记得使用@wraps(func),这样才不会丢失被装饰函数的元数据。同时,从这个例子中我们也可以看到被装饰函数的运行过程,装饰器会接管被装饰函数的所有,并返回结果。 @装饰器的重要特性就是它可以通过wrapped属性来访问被包装的函数,所以我们可以利用这个特性来解包。

1.3 对装饰器进行解包

在1.2的末尾也提到过,利用wrapped属性来进行解包。例如在1.2中可以直接使用:

@GetRunTime
def cutdown(n):
    """
    :param n:
    :return:
    """
    print('cundown is running')
    while n > 0:
        n -= 1

cutdown.__wrapped__(10000000)
打印输出:
cundown is running

当有多个装饰器的函数也可以通过这种方法来访问。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏胖胖的专栏

实战干货:从零快速搭建自己的爬虫系统

本文简要归纳了网页爬虫的基础知识,着重于利用现有组件,快速建立一套实际可用的网页爬取、分析系统。系统主要使用Python 作为开发语言,在 Linux 或 Ma...

4.5K40
来自专栏腾讯移动品质中心TMQ的专栏

如何轻松爬取网页数据?

在实际工作中,难免会遇到从网页爬取数据信息的需求,如:从微软官网上爬取最新发布的系统版本。很明显这是个网页爬虫的工作。本文将根据网站特性进行分类介绍几种使用py...

5K20
来自专栏钟志远的专栏

【腾讯云的1001种玩法】云服务器搭建Python爬虫环境

在上一篇文章中,我们已经学会了在云服务器上搭建Python环境了,假设你已经在云服务器上搭建好了Python环境,我们将进入下一步:搭建Python爬虫环境。

4K30
来自专栏张戈的专栏

Python 远程控制模块 paramiko 问题解决记录

生产环境中使用paramiko作SSH远程控制时,发现会有部分机器报Error reading SSH protocol banner错误,尝试使用ssh命令连...

6.7K20
来自专栏崔庆才的专栏

腾讯云主机Python3环境安装Scrapy爬虫框架过程及常见错误

Scrapy安装介绍Scrapy的安装有多种方式,它支持Python2.7版本及以上或Python3.3版本及以上。下面说明Python3环境下的安装过程。Sc...

2.6K10
来自专栏社区的朋友们

深度学习入门实战(二):用TensorFlow训练线性回归

上一篇文章我们介绍了 MxNet 的安装,但 MxNet 有个缺点,那就是文档不太全,用起来可能是要看源代码才能理解某个方法的含义,所以今天我们就介绍一下 Te...

6.4K10
来自专栏唐郑望的专栏

Django数据处理的一些实践

提到 Django 肯定避不开 MVC 模式,即模型(Model)-视图(View)-控制器(Controller),通过将业务逻辑、数据、界面显示分离的方法组...

38210
来自专栏张宁的专栏

反爬虫和抗DDOS攻击技术实践

企鹅媒体平台媒体名片页反爬虫技术实践,分布式网页爬虫技术、利用人工智能进行人机识别、图像识别码、频率访问控制、利用无头浏览器PhantomJS、Selenium...

2K10
来自专栏社区的朋友们

深度学习入门实战(一):像Prisma一样算法生成梵高风格画像

现在人工智能是个大热点,而人工智能离不开机器学习,机器学习中深度学习又是比较热门的方向,本系列文章就从实战出发,介绍下如何使用MXnet进行深度学习~

10.4K30
来自专栏钟志远的专栏

【腾讯云的1001种玩法】云服务器搭建Python环境

之前一直在用阿里云服务器跑爬虫、小脚本。这两天在朋友的安利下转到了腾讯云上面来,刚好趁这个机会写一写有关于云服务器上Python爬虫环境的搭建。

7.1K60

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励