专栏首页公众号:googpy清清爽爽理解Python装饰器

清清爽爽理解Python装饰器

不知不觉已经连续写了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。

本文分享自微信公众号 - googpy(googpy)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-07

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python的高级语法与用法(二)

    这种将数字转换成枚举类型的方法和字符串整形转换是不一样的,前者是数值访问具体枚举类型的方案,后者则是数据结构的内部转换。

    stormwen
  • Python2和3的区别

    学2还是3我想这是每一个初学者都会遇到的难题,我觉得作为一名新手直接上3。Python3是未来的大势所趋,2.7现在只是在维护,不会增加新的功能。

    stormwen
  • 文件处理一直在路上

    一直输出python干货,是我开这个公众号的初衷,我会把这条道路坚持走到底,也希望我写的东西对你有一点作用。我把自己每天学习python时遇到的各种问题记录下来...

    stormwen
  • Python实现简单登陆验证(文件操作)

           1.用户名的验证,首先对存储用户名和密码的信息读取,然后再把输入的用户名和从文件中读取的用户名进行比对,如果比对成功则进行下一步的密码验证,如果没...

    py3study
  • VS2017搭建驱动开发环境WDK

    先安装VS2017,然后在安装WDK,WDK会自动关联到VS2017中,不用你任何操作,自动在新建项目中可以找到驱动开发。

    战神伽罗
  • 在Keras中展示深度学习模式的训练历史记录

    通过观察神经网络和深度学习模型在训练期间的表现,你可以得知很多有用的信息。 Keras是Python中强大的库,为创建深度学习模型提供了一个简单的接口,并包装了...

    AiTechYun
  • Python3.7的新API:asyncio.run()

    Python3.7的正式版本已经发布有一段时间了,出了内置的breakpoint()断点函数,颇受争议的dataclass,自定义模块里的__getattr__...

    ★忆先★
  • 聊聊flink的JDBCAppendTableSink

    flink-jdbc_2.11-1.7.0-sources.jar!/org/apache/flink/api/java/io/jdbc/JDBCAppendT...

    codecraft
  • 好雨云帮一周问答集锦(11.7-11.13)

    Rainbond开源
  • 聊聊flink的JDBCAppendTableSink

    flink-jdbc_2.11-1.7.0-sources.jar!/org/apache/flink/api/java/io/jdbc/JDBCAppendT...

    codecraft

扫码关注云+社区

领取腾讯云代金券