Fork me on GitHub

Python装饰器

一、什么是装饰器

  装饰器自身就是一个函数,它是在函数上调用的装饰,也可以说用一个函数(装饰器)来”装饰”另一个函数。在代码中以@表示,很明显的是在某个函数之上出现了@,就说明装饰器装饰了其函数。重点来了,那么它为什么叫做装饰器呢?

>>> import time
>>> def extend_login(func):
>>>     def timestamp(*args,**kwargs):
>>>         print (time.ctime())    #打印当前系统时间
>>>         func(*args,**kwargs)
>>>     return timestamp    #注意这里不能加括号,因为return的是timestamp的内存地址,不可写为timestamp()
>>> 
>>> @extend_login
>>> def login(username):
>>>     print ("%s login system" % username)
>>> 
>>> login('Stanley')

  以上代码中,extend_login 就是装饰器的名称,它是一个函数,接收func作为这个函数的参数。因为在执行exntend_login函数的时候,并没有立即执行timestamp函数,而是将timestamp生成内存地址(图1),下一步直接return了timestamp的内存地址到login函数,此时的login函数已经不再是原来的它,经过了extend_login函数的装饰,已经变为了login = extend_login(login),这里的login是其内存地址;最后执行执行login函数(也就是timestamp函数。所谓装饰器是指在执行func函数之前,又执行了其他的操作(打印当前系统时间),所以说起到了装饰func函数的作用,其功能是在用户登陆之前,打印当前系统时间,这就是一个装饰器。

999

图1

二、如何使用装饰器

  装饰器到底有什么使用的场景能让它物有所用呢,大多数的场景是在函数不修改原有函数的基础上,在其外部扩展一个函数的行为,修改函数或扩展原有功能;另一方如果这个功能可以被使用在很多函数上,或是函数并不是自己实现,那可以写个装饰器来实现这些功能,而不用重复编写,减少代码的冗余度。

>>> @extend_login
>>> def login():
>>>     pass

  在装饰器使用过程中,@extend_login含义是调用名为exntend_login的装饰器(其实就是个函数)来装饰login函数,那么按照如上调用等价于:

>>> login = extend_login(login)    #这里括号内的login没有(),仅仅是吧login的内存地址当做参数传递给extend_login装饰器(函数)

三、装饰器内传递参数

  在给装饰器内传递参数的时候,需要注意的是在timestamp函数内,要写多个接收参数和接收任意类型参数,也就是*args和**kwargs;如果这里没有指定接收参数,那么在login函数向装饰器内传递参数会出现报错。

>>> import time
>>> def extend_login(func):
>>>     def timestamp():    #没有参数会报错
>>>         print (time.ctime())
>>>         func()    #没有参数会报错
>>>     return timestamp
>>> 
>>> @extend_login
>>> def login(username):
>>>     print ("%s login system" % username)
>>> 
>>> login('Stanley')
TypeError: timestamp() takes no arguments (1 given)

  在装饰器调用中,会把login函数的参数传递给装饰器(图2)

869426-20160201153530366-1693317262

图2

四、完整示例

>>> import time
>>> def extend_login(func):
>>>     def timestamp(*args,**kwargs):
>>>         print (time.ctime())
>>>         func(*args,**kwargs)
>>>     return timestamp
>>> 
>>> @extend_login
>>> def login(username):
>>>     print ("%s login system" % username)
>>> 
>>> login('Stanley')

Mon Feb 01 11:29:40 2016
Stanley login system
posted @ 2016-02-01 22:20  stefan.liu  阅读(239)  评论(0编辑  收藏  举报