面试系列 | 带你彻底搞懂 Python 装饰器

本文字数:2489 字

阅读本文大概需要:6 分钟

写在之前

「装饰器」作为 Python 高级语言特性中的重要部分,是修改函数的一种超级便捷的方式,适当使用能够有效提高代码的可读性和可维护性,非常的便利灵活。

「装饰器」本质上就是一个函数,这个函数的特点是可以接受其它的函数当作它的参数,并将其替换成一个新的函数(即返回给另一个函数)。

可能现在这么看的话有点懵,为了深入理解「装饰器」的原理,我们首先先要搞明白「什么是函数对象」,「什么是嵌套函数」,「什么是闭包」。关于这三个问题我在很久以前的文章中已经写过了,你只需要点击下面的链接去看就好了,这也是面试中常问的知识哦:

零基础学习 Python 之函数对象

零基础学习 Python 之嵌套函数

零基础学习 Python 之闭包

装饰器

搞明白上面的三个问题,其实简单点来说就是告诉你:函数可以赋值给变量,函数可嵌套,函数对象可以作为另一个函数的参数

首先我们来看一个例子,在这个例子中我们用到了前面列出来的所有知识:

def first(fun):
        def second():
                print('start')
                fun()
                print('end')
                print fun.__name__
        return second

def man():
        print('i am a man()')

f = first(man)
f()

上述代码的执行结果如下所示:

start
i am a man()
end
man

上面的程序中,这个就是 first 函数接收了 man 函数作为参数,并将 man 函数以一个新的函数进行替换。看到这你有没有发现,这个和我在文章刚开始时所说的「装饰器」的描述是一样的。既然这样的话,那我们就把上述的代码改造成符合 Python 装饰器的定义和用法的样子,具体如下所示:

def first(func):
       def second():
               print('start')
               func()
               print('end')
               print (func.__name__)
       return second

@first
def man():
       print('i am a man()')

man()

上面这段代码和之前的代码的作用一模一样。区别在于之前的代码直接“明目张胆”的使用 first 函数去封装 man 函数,而上面这个是用了「语法糖」来封装 man 函数。至于什么是语法糖,不用细去追究,你就知道是类似「@first」这种形式的东西就好了。

在上述代码中「@frist」在 man 函数的上面,表示对 man 函数使用 first 装饰器。「@」 是装饰器的语法,「first」是装饰器的名称。

下面我们再来看一个复杂点的例子,用这个例子我们来更好的理解一下「装饰器」的使用以及它作为 Python 语言高级特性被人津津乐道的部分:

def check_admin(username):
        if username != 'admin':
                raise Exception('This user do not have permission')

class Stack:
        def __init__(self):
                self.item = []

        def push(self,username,item):
                check_admin(username=username)
                self.item.append(item)

        def pop(self,username):
                check_admin(username=username)
                if not self.item:
                        raise Exception('NO elem in stack')
                return self.item.pop()

上述实现了一个特殊的栈,特殊在多了检查当前用户是否为 admin 这步判断,如果当前用户不是 admin,则抛出异常。上面的代码中将检查当前用户的身份写成了一个独立的函数 check_admin,在 push 和 pop 中只需要调用这个函数即可。这种方式增强了代码的可读性,减少了代码冗余,希望大家在编程的时候可以具有这种意识。

下面我们来看看上述代码用装饰器来写成的效果:

def check_admin(func):
        def wrapper(*args, **kwargs):
                if kwargs.get('username') != 'admin':
                        raise Exception('This user do not have permission')
                return func(*args, **kwargs)
        return wrapper

class Stack:
        def __init__(self):
                self.item = []

        @check_admin
        def push(self,username,item):
                self.item.append(item)

        @check_admin
        def pop(self,username):
                if not self.item:
                        raise Exception('NO elem in stack')
                return self.item.pop()

PS:可能很多人对 *args 和 **kwargs 不太熟悉,详情请戳下面的链接:

Python 拓展之 *args & **kwargs

对比一下使用「装饰器」和不使用装饰器的两种写法,乍一看,好像使用「装饰器」以后代码的行数更多了,但是你有没有发现代码看起来好像更容易理解了一些。在没有装饰器的时候,我们先看到的是 check_admin 这个函数,我们得先去想这个函数是干嘛的,然后看到的才是对栈的操作;而使用装饰器的时候,我们上来看到的就是对栈的操作语句,至于 check_admin 完全不会干扰到我们对当前函数的理解,所以使用了装饰器可读性更好了一些

就和我在之前的文章中所讲的「生成器」那样,虽然 Python 的高级语言特性好用,但也不能乱用。装饰器的语法复杂,通过我们在上面缩写的装饰器就可以看出,它写完以后是很难调试的,并且使用「装饰器」的程序的速度会比不使用装饰器的程序更慢,所以还是要具体场景具体看待。

本文分享自微信公众号 - Python空间(Devtogether)

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

原始发表时间:2019-02-28

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菲宇

jieba分词器详解及python实战

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

13420
来自专栏菲宇

Python操作MongoDB

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

6530
来自专栏菲宇

Selenium常见元素定位方法和操作的学习介绍

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

10820
来自专栏菲宇

Python Django使用HttpResponse返回图片并显示

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

14740
来自专栏浊酒清味

Python进阶之Matplotlib入门(二)

Matplotlib是Python的画图领域使用最广泛的绘图库,它能让使用者很轻松地将数据图形化以及利用它可以画出许多高质量的图像,是用Python画图的必备技...

9230
来自专栏菲宇

python的super()的作用和原理

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

7120
来自专栏python编程军火库

python coding

各位小伙伴大家好哈,国庆过的如何呢,今天我们分享一下GUI编程部分的一个综合例子,帮助大家来巩固一下这部分的内容,从此之后妈妈再也不用担心我给自...

10720
来自专栏浊酒清味

Python进阶之Matplotlib入门(三)

Matplotlib是Python的画图领域使用最广泛的绘图库,它能让使用者很轻松地将数据图形化以及利用它可以画出许多高质量的图像,是用Python画图的必备技...

8820
来自专栏菲宇

Django实现统计网站访问次数、访问 ip 、受访页面

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

18730
来自专栏python学习教程

「新手必看」如何安装Python解释器

⒉对于测试而言学习python这门语言更多就是为自动化做代码的积累,众多后台语言中选择python语言可能是python语言本身的特点,语法简洁 易于小白上手,...

6720

扫码关注云+社区

领取腾讯云代金券

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