个性化阅读
专注于IT技术分析

python3装饰器decorator – Python3教程

上一章Python教程请查看:python3闭包closure

装饰器接受一个函数,添加一些功能并返回它,在本文中,你将了解如何创建装饰器decorator以及为什么要使用它。

Python中的装饰器是什么?

Python有一个有趣的特性,称为装饰器,用于向现有代码添加功能。

这也称为元编程,因为程序的一部分试图在编译时修改程序的另一部分。

学习装饰器的先决条件

为了理解decorator,我们必须首先了解Python中的一些基本知识。

我们必须接受这样一个事实:Python中的一切(甚至类)都是对象。我们定义的名称只是绑定到这些对象的标识符,函数也不例外,它们也是对象(带有属性),可以将各种不同的名称绑定到同一个函数对象。

这里有一个例子。

def first(msg):
    print(msg)    

first("Hello")

second = first
second("Hello")

当你运行代码时,第一个和第二个函数都给出相同的输出。在这里,第一个和第二个名称引用同一个函数对象。

现在事情变得更奇怪了。

函数可以作为参数传递给另一个函数。

如果你在Python中使用过map、filter和reduce等函数,那么你应该已经知道了。

以其他函数为参数的函数也称为高阶函数,下面就是这样一个函数的例子。

def inc(x):
    return x + 1

def dec(x):
    return x - 1

def operate(func, x):
    result = func(x)
    return result

我们按如下方式调用该函数。

>>> operate(inc,3)
4
>>> operate(dec,3)
2

此外,一个函数可以返回另一个函数。

def is_called():
    def is_returned():
        print("Hello")
    return is_returned

new = is_called()

#输出 "Hello"
new()

在这里,is_returned()是一个嵌套函数,它是在每次调用is_called()时定义并返回的。

最后,我们必须了解Python中的闭包。

回到装饰器

函数和方法被称为可调用的。

事实上,任何实现了特殊方法_call__()的对象都被称为可调用的,因此,从最基本的意义上说,decorator是一个返回callable的callable。

基本上,decorator接受一个函数,添加一些功能并返回它。

def make_pretty(func):
    def inner():
        print("我有装饰")
        func()
    return inner

def ordinary():
    print("我是普通的")

在shell中运行以下代码时,

>>> ordinary()
我是普通的
>>> # 我们来装饰一下这个普通的函数
>>> pretty = make_pretty(ordinary)
>>> pretty()
我有装饰
我是普通的

在上面的例子中,make_pretty()是一个装饰器。在赋值步骤中。

pretty = make_pretty(ordinary)

函数ordinary()被修饰,返回的函数被命名为pretty。

我们可以看到decorator函数在原来的函数中添加了一些新功能,这类似于包装礼物,装饰器充当包装器,被装饰的物品(里面的礼物)的性质不会改变,但是现在,它看起来很漂亮。

通常,我们修饰一个函数并将其重新赋值为,

ordinary = make_pretty(ordinary).

这是一个常见的构造,因此Python有一个语法来简化它。

我们可以使用@符号和装饰器函数的名称,并将其置于要装饰的函数的定义之上。例如,

@make_pretty
def ordinary():
    print("我是普通的")

相当于:

def ordinary():
    print("我是普通的")
ordinary = make_pretty(ordinary)

这只是实现decorator的一种语法糖。

带有参数的装饰函数

上面的装饰器很简单,它只对没有任何参数的函数起作用,如果我们有如下参数的函数呢?

def divide(a, b):
    return a/b

这个函数有两个参数,a和b,我们知道,如果我们把b作为0传递,它会报错。

>>> divide(2,5)
0.4
>>> divide(2,0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero

现在让我们创建一个decorator来检查这种会导致错误的情况。

def smart_divide(func):
   def inner(a,b):
      print("开始执行除法:",a,"和",b)
      if b == 0:
         print("不能计算!")
         return

      return func(a,b)
   return inner

@smart_divide
def divide(a,b):
    return a/b

如果出现错误条件,这个新实现将返回None。

>>> divide(2,5)
开始执行除法: 2 和 5
0.4
>>> divide(2,0)
开始执行除法: 2 和 0
不能计算!

通过这种方式,我们可以修饰带有参数的函数。

敏锐的观察者会注意到,装饰器内嵌套的inner()函数的参数与它装饰的函数的参数相同,考虑到这一点,现在我们可以让通用装饰器使用任意数量的参数。

在Python中,这个魔术是作为函数(*args, **kwargs)完成的,这样,args将是位置参数的元组,而kwargs将是关键字参数的字典,这样的装饰器就是一个例子。

def works_for_all(func):
    def inner(*args, **kwargs):
        print("我可以装饰任何函数")
        return func(*args, **kwargs)
    return inner

Python中的链接装饰器

在Python中可以链接多个装饰器decorator。

也就是说,一个函数可以使用不同(或相同)的装饰器进行多次装饰,我们只需将装饰器置于所需的函数之上。

def star(func):
    def inner(*args, **kwargs):
        print("*" * 30)
        func(*args, **kwargs)
        print("*" * 30)
    return inner

def percent(func):
    def inner(*args, **kwargs):
        print("%" * 30)
        func(*args, **kwargs)
        print("%" * 30)
    return inner

@star
@percent
def printer(msg):
    print(msg)
printer("Hello")

使用上面的语法:

@star
@percent
def printer(msg):
    print(msg)

相当于:

def printer(msg):
    print(msg)
printer = star(percent(printer))

我们链接装饰的顺序很重要,如果我们把顺序反过来:

@percent
@star
def printer(msg):
    print(msg)
赞(0)
未经允许不得转载:srcmini » python3装饰器decorator – Python3教程

评论 抢沙发

评论前必须登录!