page contents

什么是装饰器?

轩辕小不懂 发布于 2021-11-11 16:18
阅读 502
收藏 0
分类:Python开发
2392
Nen
Nen
- 程序员

「装饰器」作为 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()



请先 登录 后评论