前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >清清爽爽理解Python装饰器

清清爽爽理解Python装饰器

作者头像
stormwen
发布2019-08-05 10:57:07
2960
发布2019-08-05 10:57:07
举报
文章被收录于专栏:公众号:googpy公众号:googpy

不知不觉已经连续写了13天了,很享受每天写公众号这个过程,通过写作将自己每天学习的Python知识分享出来,但是学习的东西是零散的,需要自己通过一定的逻辑顺序将零散的知识串起来,这很锻炼自己的逻辑能力和写作能力。

其实我也很讨厌很多知识混杂在一起,让人摸不着头绪,但是每当自己整理好一个知识点后,就觉得非常清爽,理清了头绪、巩固了知识。

今天一起学习一下Python里面装饰器这个概念吧!

需要实现记录多个函数运行的时间这个功能,那最直接的做法如下所示

import time

def f1():
    print(time.time())
    print('This is a function')


def f2():
    print(time.time())
    print('This is a function')

f1()
f2()
1557198935.042486          
This is a function
1557198935.042486
This is a function

但是,这样做是违背Python的原则——对修改是封闭的,对扩展是开放的。

于是可以稍加修改,为了打印两个函数的运行时间,又单独编写了一个专门打印时间的函数,将函数作为一个变量传入到这个打印时间的函数中,然后在下面进行调用。

import time

def f1():
    print('This is a function')

def f2():
    print('This is a function')

def print_current_time(func):
    print(time.time())
    func()

print_current_time(f1)
print_current_time(f2)

但是这段代码也不好,表面看着由一个打印时间的函数负责,其实打印时间的这个函数和其他的两个函数相关联性很不好,它的实质和下面这段代码是没区别的。

import time

def f1():
    print(time.time())

def f2():
    print(time.time())

print('This is a function')
f1()
print('This is a function')
f2()

为了解决这个问题,我们就需要用到今天的主角——装饰器

重新定义一个装饰器函数,再嵌套一个wrapper函数,这个函数主要负责封装。具体代码如下:

import time

def decorator(func):     #装饰器
    def wrapper():       #被封装
        print(time.time())
        func()
    return wrapper

def f1():
    print('This is a function')

f = decorator(f1)
f()

大家可以看到虽然定义了装饰器这个函数,但是调用的时候依然很麻烦,和上面定义一个打印时间的函数没什么区别,看不出来有什么优势?

为了进一步说明装饰器的优势,这里需要引入语法糖这个概念。直接在函数f1的前面加入语法糖,就可以实现打印时间的功能。

import time

def decorator(func):     #装饰器
    def wrapper():       #被封装
        print(time.time())
        func()
    return wrapper

@decorator
def f1():
    print('This is a function')

f1()

大家可以看到这里,通过直接调用f1()就可以实现功能。

现在考虑给2个函数打印运行时间,而且给两个函数传入不同个数的参数,比如说,f1(func_name)、f2(func_name1,func_name2),那该怎么实现这个功能呢?

在这里装饰器只有一个,我们怎么将它变成一个通用的,体现出装饰器的复用性?这里需要用到可变参数args这个概念,它表示一组参数,具体操作如下:

import time

def decorator(func):     #装饰器
    def wrapper(*args):  #被封装   可变参数args表示一组参数
        print(time.time())
        func(*args)
    return wrapper

@decorator
def f1(func_name):
    print('This is a function'+func_name)

@decorator
def f2(func_name1,func_name2):
    print('This is a function' + func_name1)
    print('This is a function' + func_name2)

f1('test func')
f2('test func1','test func2')

如果再将难度提升一下,在前两个函数的基础,增加第三个函数,且第三个函数传入三个参数,那又该怎么操作呢?

这里需要用到**kw这个形参,它表示一个字典,将它传入到wrapper函数中,具体代码如下

import time

def decorator(func):     #装饰器
    def wrapper(*args,**kw):  #被封装
        print(time.time())
        func(*args,**kw)
    return wrapper

@decorator
def f1(func_name):
    print('This is a function'+func_name)

@decorator
def f2(func_name1,func_name2):
    print('This is a function' + func_name1)
    print('This is a function' + func_name2)

@decorator
def f3(func_name1,func_name2,**kw):
    print('This is a function' + func_name1)
    print('This is a function' + func_name2)
    print(kw)

f1('test func')
f2('test func1','test func2')
f3('test func1','test func2',a=1,b=2,c='1,2,3')

关于装饰器就学到这,对于一个初学者来说,了解这些基本的装饰器已经够了,平时在自己编码的过程中,可以根据业务需求,有意识的用到装饰器,这样会让你的代码更加fanastic。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 googpy 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档