Python深入学习之装饰器_python

装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。

装饰器最早在Python 2.5中出现,它最初被用于加工函数和方法这样的可调用对象(callable object,这样的对象定义有__call__方法)。在Python 2.6以及之后的Python版本中,装饰器被进一步用于加工类。

装饰函数和方法

我们先定义两个简单的数学函数,一个用来计算平方和,一个用来计算平方差:

复制代码 代码如下:

# get square sum
def square_sum(a, b):
    return a**2 + b**2

# get square diff
def square_diff(a, b):
    return a**2 - b**2

print(square_sum(3, 4))
print(square_diff(3, 4))

在拥有了基本的数学功能之后,我们可能想为函数增加其它的功能,比如打印输入。我们可以改写函数来实现这一点:

复制代码 代码如下:

# modify: print input

# get square sum
def square_sum(a, b):
    print("intput:", a, b)
    return a**2 + b**2

# get square diff
def square_diff(a, b):
    print("input", a, b)
    return a**2 - b**2

print(square_sum(3, 4))
print(square_diff(3, 4))

我们修改了函数的定义,为函数增加了功能。

现在,我们使用装饰器来实现上述修改:

复制代码 代码如下:

def decorator(F):
    def new_F(a, b):
        print("input", a, b)
        return F(a, b)
    return new_F

# get square sum
@decorator
def square_sum(a, b):
    return a**2 + b**2

# get square diff
@decorator
def square_diff(a, b):
    return a**2 - b**2

print(square_sum(3, 4))
print(square_diff(3, 4))

装饰器可以用def的形式定义,如上面代码中的decorator。装饰器接收一个可调用对象作为输入参数,并返回一个新的可调用对象。装饰器新建了一个可调用对象,也就是上面的new_F。new_F中,我们增加了打印的功能,并通过调用F(a, b)来实现原有函数的功能。

定义好装饰器后,我们就可以通过@语法使用了。在函数square_sum和square_diff定义之前调用@decorator,我们实际上将square_sum或square_diff传递给decorator,并将decorator返回的新的可调用对象赋给原来的函数名(square_sum或square_diff)。 所以,当我们调用square_sum(3, 4)的时候,就相当于:

复制代码 代码如下:

square_sum = decorator(square_sum)
square_sum(3, 4)

我们知道,Python中的变量名和对象是分离的。变量名可以指向任意一个对象。从本质上,装饰器起到的就是这样一个重新指向变量名的作用(name binding),让同一个变量名指向一个新返回的可调用对象,从而达到修改可调用对象的目的。

与加工函数类似,我们可以使用装饰器加工类的方法。

如果我们有其他的类似函数,我们可以继续调用decorator来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

含参的装饰器

在上面的装饰器调用中,比如@decorator,该装饰器默认它后面的函数是唯一的参数。装饰器的语法允许我们调用decorator时,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。

复制代码 代码如下:

# a new wrapper layer
def pre_str(pre=''):
    # old decorator
    def decorator(F):
        def new_F(a, b):
            print(pre + "input", a, b)
            return F(a, b)
        return new_F
    return decorator

# get square sum
@pre_str('^_^')
def square_sum(a, b):
    return a**2 + b**2

# get square diff
@pre_str('T_T')
def square_diff(a, b):
    return a**2 - b**2

print(square_sum(3, 4))
print(square_diff(3, 4))

上面的pre_str是允许参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有环境参量的闭包。当我们使用@pre_str('^_^')调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。该调用相当于:

复制代码 代码如下:

square_sum = pre_str('^_^') (square_sum)

装饰类

在上面的例子中,装饰器接收一个函数,并返回一个函数,从而起到加工函数的效果。在Python 2.6以后,装饰器被拓展到类。一个装饰器可以接收一个类,并返回一个类,从而起到加工类的效果。

复制代码 代码如下:

def decorator(aClass):
    class newClass:
        def __init__(self, age):
            self.total_display   = 0
            self.wrapped         = aClass(age)
        def display(self):
            self.total_display += 1
            print("total display", self.total_display)
            self.wrapped.display()
    return newClass

@decorator
class Bird:
    def __init__(self, age):
        self.age = age
    def display(self):
        print("My age is",self.age)

eagleLord = Bird(5)
for i in range(3):
    eagleLord.display()

在decorator中,我们返回了一个新类newClass。在新类中,我们记录了原来类生成的对象(self.wrapped),并附加了新的属性total_display,用于记录调用display的次数。我们也同时更改了display方法。

通过修改,我们的Bird类可以显示调用display的次数了。

总结

装饰器的核心作用是name binding。这种语法是Python多编程范式的又一个体现。大部分Python用户都不怎么需要定义装饰器,但有可能会使用装饰器。鉴于装饰器在Python项目中的广泛使用,了解这一语法是非常有益的。

时间: 2024-08-12 22:04:25

Python深入学习之装饰器_python的相关文章

Python中的多重装饰器_python

多重装饰器,即多个装饰器修饰同一个对象[实际上并非完全如此,且看下文详解] 1.装饰器无参数: 复制代码 代码如下: >>> def first(func):     print '%s() was post to first()'%func.func_name     def _first(*args,**kw):         print 'Call the function %s() in _first().'%func.func_name         return func

Python合并多个装饰器小技巧

  这篇文章主要介绍了Python合并多个装饰器小技巧,本文用改写调用函数的方式实现把多个装饰器合并成一行.一个函数来调用,需要的朋友可以参考下 django程序,需要写很多api,每个函数都需要几个装饰器,例如   代码如下: @csrf_exempt @require_POST def foo(request): pass 既然那么多个方法都需要写2个装饰器,或者多个,有啥办法把多个合并成一行呢? 上面的函数执行过程应该是 代码如下: csrf_exempt(require_POST(foo

Python中利用函数装饰器实现备忘功能_python

"备忘"的定义 "memoization"(备忘)这个词是由Donald Michie在1968年提出的,它基于拉丁语单词"memorandum"(备忘录),意思是"被记住".虽然它和单词"memorization"在某种程度上有些相似,但它并不是该单词的错误拼写.实际上,Memoisation是一种用于通过计算来加速程序的技术,它通过记住输入量的计算结果,例如函数调用结果,来实现其加速目的.如果遇到相同的

Python中的各种装饰器详解_python

Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: 复制代码 代码如下: >>> def test(func):     def _test():         print 'Call the function %s().'%func.func_name         return func()     return _test >

Python自动重试HTTP连接装饰器_python

有时候我们要去别的接口取数据,可能因为网络原因偶尔失败,为了能自动重试,写了这么一个装饰器. 这个是python2.7x 的版本,python3.x可以用 nonlocal 来重写. #-*- coding: utf-8 -*- #all decorators in this tool file #author: orangleliu ############################################################ #http连接有问题时候,自动重连 de

Python合并多个装饰器小技巧_python

django程序,需要写很多api,每个函数都需要几个装饰器,例如 复制代码 代码如下: @csrf_exempt  @require_POST  def  foo(request):      pass  既然那么多个方法都需要写2个装饰器,或者多个,有啥办法把多个合并成一行呢? 上面的函数执行过程应该是 复制代码 代码如下: csrf_exempt(require_POST(foo))  修改成 复制代码 代码如下: def compose(*funs):      def deco(f):

【Python】浅谈装饰器

一 装饰器是什么    装饰器是一个用于封装函数或者类的代码工具,显式地将封装器作用于函数或者类上,达到程序运行时动态增加功能的目的.对于函数运行前处理常见前置条件(常见的web登陆授权验证),或者在函数执行之后做善后工作(比如异常处理,记录log 等等). 二 如何使用装饰器    装饰器本质上就是一个可用接受调用也可以返回调用的高阶函数.该函数以被装饰的函数为参数(还可以加上其他值作为参数).在装饰器内进行装饰器的逻辑处理,执行被装饰函数,并返回一个装饰过的函数,听起来是不是有点绕,Talk

PHP、Python和Javascript的装饰器模式对比_php实例

修饰模式(Decorator Pattern),又叫装饰者模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式.就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能.装饰模式非常适用于灵活扩展对象的功能,下面是装饰模式的UML图: 例如,有一个技术论坛,用户通过留言进行沟通,由于刚开始论坛里都是熟人,几乎都不需要对留言的内容作出审核,接收留言的页面可以是这样: class SaveMsg(){ private $msg; public funct

Selenium2+python自动化55-unittest之装饰器(@classmethod)

前言 前面讲到unittest里面setUp可以在每次执行用例前执行,这样有效的减少了代码量,但是有个弊端,比如打开浏览器操作,每次执行用例时候都会重新打开,这样就会浪费很多时间. 于是就想是不是可以只打开一次浏览器,执行完用例再关闭呢?这就需要用到装饰器(@classmethod)来解决了.   一.装饰器 1.用setUp与setUpClass区别 setup():每个测试case运行前运行 teardown():每个测试case运行完后执行 setUpClass():必须使用@classm