Python装饰器
简介
Python装饰器本质上是一个函数,它可以让其他函数不做代码变动的情况下,增加额外的功能,其返回值是增加功能后的新函数,可抽离出常用的修饰代码作为装饰器,增强了代码的可重用性.
装饰器
简单的装饰器
def foo():
print "I am foo"
添加一个新的需求,输出关于该函数函数名的信息 –>
import logging
def foo():
print "I am foo"
logging.warning("foo is running")
现在有一新函数foo2也想实现该新需求 –>
import logging
def add_loginfo(func):
logging.warning("%s is running"%func.__name__)
func()
def foo2():
print "I am foo2"
上述代码实现了需求,但改变了代码结构,原结构为调用foo2,如下:
import logging
def foo2():
logging.warning("foo2 is runing")
print "I am foo2"
在这可以用装饰器实现代码结构的保留:
#coding=utf-8
import logging
###########################
###
def add_loginfo(func):
#参数是不确定的,所以用*args,*kwargs
def wrapper(*args, **kwargs):
logging.warning("%s is running"%func.__name__)
return func(*args, **kwargs)
return func(*args, **kwargs)
###
###########################
def foo2:
print "I am foo2"
############################
###
foo2 = add_loginfo(foo2)
###
############################
foo2()
显然在实现新需求的同时,逻辑结构未发生改变
运行结果如下:
WARNING:root:foo2 is running
I am foo2
add_loginfo 函数 就可以提取成一个装饰器,如下:
import logging
def add_loginfo(func):
#参数是不确定的,所以用*args,*kwargs
def wrapper(*args, **kwargs):
logging.warning("%s is running"%func.__name__)
return func(*args, **kwargs)
return wrapper
@add_loginfo
def foo():
print "I am foo"
@add_loginfo
def foo2():
print "I am foo2"
foo()
foo2()
运行结果如下:
WARNING:root:foo is running
I am foo
WARNING:root:foo2 is running
I am foo2
当装饰器的参数为类时:
#coding=utf-8
from functools import wraps
def singleton(cls):
_instance = {}
@wraps
def _singleton(*args ,**kwargs):
if cls not in _instance:
_instance[cls] = cls(*args ,**kwargs)
return _instance[cls]
return _singleton
@singleton
class A(object):
def __init__(self ,b):
self.b = b
def test(self):
print self.b
a1 = A(1)
a2 = A(2)
print A.func_name
print type(A)
print type(a1)
print "a1:",id(a1)
print "a2:",id(a2)
a1.test()
a2.test()
这是利用装饰器实现的一个单例模式,类A传入装饰器后返回一个函数,此函数传入合适的参数能生成原先类的实例
运行结果如下:
A
<type 'function'>
<class '__main__.A'>
a1: 139648281857744
a2: 139648281857744
1
1
带参装饰器
带参装饰器可以用闭包实现
(闭包将在另一篇博文研究)
import logging
def add_loginfo(info):
def decorator(func):
def wrapper(*args, **kwargs):
if info:
print info
logging.warning("%s is running"%func.__name__)
return func(*args)
return wrapper
return decorator
@add_loginfo(info="FBI warning")
def foo(name):
print "I am %s"%name
foo('wk')
运行结果如下:
FBI warning:
WARNING:root:foo is running
I am wk
元信息
函数经过装饰器后返回的是return出的函数,上述例子中为wrapper,自然,__doc__,__name__都变成wrapper的了,好在有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中.
import logging
from functools import wraps
def add_loginfo(info):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
if info:
print info
logging.warning("%s is running"%func.__name__)
return func(*args)
return wrapper
return decorator
@add_loginfo(info="FBI warning")
def foo(name):
print "I am %s"%name
print foo.__name__
foo('wk')
运行结果如下:
foo
FBI warning:
WARNING:root:foo is running
I am wk
类装饰器
优点:灵活度大,高内聚,封装性强
实现:使用__init__传入目标,使用__call__调用目标
class Foo():
def __init__(self,func):
self.funcIn = func
def __call__(self):
print "hello world"
self.funcIn()
@Foo
def foo():
print 'I am foo'
foo()
运行结果如下:
hello world
I am foo
常用装饰器
- “@classmethod”:声明类方法
- “@staticmethod”:声明静态方法
- “@property”:将类方法转换为只读属性和重新实现一个属性的setter和getter方法