Python学习日志程序员程序猿阵线联盟-汇总各类技术干货

【第十八天】装饰器

2018-03-30  本文已影响12人  人生苦短_我用Python

7.3

1.装饰器

装饰器(decorator)是一种高级py语法,装饰器可以对一个函数,方法或者类进行加工
在py中,我们有多种方法对函数和类进行加工,装饰器从操作上入手
为函数增加额外的指令,py最初没有装饰器这一语法
装饰器在py2.5中才出现,最初只用于函数
在py2.6以及之后的py版本中,装饰器被进一步用于类

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

#获得平方和
def square_sum(a,b):
    return a**2 + b**2  

#获得平方差
def square_diff(a,b):
    return a**2 - b**2
    
if __name__ == '__main__':
    print(square_sum(3,4))    #打印25
    print(square_diff(3,4))   #打印-7

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

#装饰:打印输入

def square_sum(a,b):
    print('input:',a,b)
    return a**2 + b**2

def square_diff(a,b):
    print('input:',a,b)
    return a**2 - b**2
    
if __name__ == '__main__':
    print(square_sum(3,4))
    print(square_diff(3,4))

我们修改了函数定义,为函数增加了功能,从代码中可以看到
这两个函数在功能上的拓展有很高的相似性
都是增加了print('input:',a,b)这一打印功能
我们可以改用装饰器,定义功能拓展本身
再把装饰器用于两个函数:

def decorator_demo(old_function):
    def new_function(a,b):
        print('input',a,b)    #额外打印操作
        return old_function(a,b)
    return new_function

@decorator_demo
def square_sum(a,b):
    return a**2 + b**2
    
@decorator_demo
def square_diff(a,b):
    return a**2 - b**2

if __name__ == '__main__':
    print(square_sum(3,4))
    print(square_diff(3,4))

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

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

square_sum = decorator_demo(square_sum)
square_sum(3,4)

我们知道,py中的变量名和对象是分离的
变量名其实是指向一个对象的引用
从本质上,装饰器起到的作用就是名称绑定(name binding)
让同一个变量名指向一个新返回的函数对象,从而达到修改函数对象的目的
只不过,我们很少彻底更改函数对象,在使用装饰器时
我们往往会在新函数内部调用旧的函数,以便保留旧函数功能

下面看一个更有实用功能的装饰器,我们可以利用time包来测量程序运行的时间
把测量程序运行时间的功能做成一个装饰器,将这个装饰器运用于其他函数
将显示函数的实际运行时间:

import time

def decorator_timer(old_function):
    def new_function(*arg,**dict_arg):
        t1 = time.time()
        result = old_function(*arg,**dict_arg)
        t2 = time.time()
        print('time:',t2 - t1)
        return result
    return new_function
@decorator_timer
def sum(a,b):
    c = a + b
    return c
if __name__ == '__main__':
    print(sum(3,4))
time: 1.1920928955078125e-06
7

在new_function()中,除调用旧函数外
还前后额外调用了一次time.time(),由于time.time()返回挂钟时间
它们的差值反映了旧函数的运行时间,此外,我们通过打包参数的方法
可以在新函数和旧函数之间传递所有的参数

装饰器可以实现代码的可复用性,我们可以用同一个装饰器修饰多个函数
以便实现相同的附加功能,比如说,在建设网站服务器时,我们能用不同函数
表示对不同HTTP请求的处理,当我们每次处理HTTP请求前
都想附加一个客户验证功能时,那么就可以定义一个统一的装饰器
作用于每一个处理函数,这样,程序能重复利用,可读性也大为提高

Python中的函数的参数定义和可变参数
https://www.cnblogs.com/tqsummer/archive/2011/01/25/1944416.html

上一篇下一篇

猜你喜欢

热点阅读