|
Python装饰器
什么是Python的装饰器?装饰器的英文名是decorator,它的本质是利用动态语言的特性,改变、过滤、记录已有类、函数的行为或对象,它可以进行命名的重新绑定,借此进行对象的管理。
为什么使用装饰器?语法明确清楚,使用方便。
装饰器可以是一个函数或者类,它是一个返回可调用对象的可调用对象。就是说,调用它,返回一个可以再次调用的对象。而这个对象参数经常有所不同。这样就把原来的对象“包裹”了起来。
它实际上把下面展示的第一行映射为第二行:
func(6)
decorator(func)(6)
也相当于:
@decorator
class c:
--->
class c:
...
C = decorator(c)
...
众所周知,Python是一种动态语言,所谓动态语言,是相对于编译型的静态语言 - C/C++等语言来说的。动态,就是可以在运行时改变程序结构、对象的类型,产生和删除函数等,而这些在编译型的语言看来是很难做到甚至是做不到的。
装饰器利用了python语言的几个特性:嵌套函数、闭包。函数在python语言中,是“一等对象”,所谓“一等对象”,就是说函数与其它类型的对象没有根本差别,可以跟其它类型对象一样,产生、传递、赋值、计算、删除。这种概念上的抽象带来了极大的优点和进步,能轻易的做到过去的语言很难做到的任务。闭包则利用了嵌套函数这点特性,扩展出一个新的概念:生命周期链。就是在闭包代码执行的过程中,代码的上下文环境构成了一套“微型代码环境”包,里面的自变量并不随着本地函数作用域的退出而清除,而是在更大范围上,构成了作用域范围。
基于这些特性,装饰器可以执行几种任务:
装饰函数,对装饰的函数进行注册登记、检查管理,然后返回这个函数。
def decorator(f):
#process function f
return f
@decorator
def func():
...
装饰函数,插入逻辑拦截函数的随后调用,然后返回一个不同的函数。
def decorator(f):
def wrapper(*args):
#use f and args
#f(*args) calls original function
return wrapper #返回新的对象
@decorator
def func(x,y)
...
func(1,2)
装饰类,函数和类的组合使用。注意,装饰器的调用在创建实例的时候就开始了。
def decorator(c):
#process class c
return c
@decorator
class c:...
装饰类,返回不同的类对象。
def decorator(cls):
class wrapper:
def __init__(self,*args):
self.wrapped = cls(*args)
def __getattr__(self,name):
return getattr(self.wrapped,name)
return wrapper
@decorator
class C:
def __init__(self,x,y):
self.attr = 'spam'
x = C(6,8)
装饰器可以使用参数,这些参数实际上传递给了真正返回的可调用对象。装饰器参数实际上在装饰发生前就解析了,保持状态一直到供随后的调用使用。
装饰器参数往往意味着可调用对象的三个层级:接受装饰器参数的一个可调用对象,它返回一个可调用对象作为装饰器。这个装饰器返回一个可调用对象来处理对最初的函数和类的调用。这三个层级每一个都可能是一个函数或者类,并且可能以作用域或类属性的形式保存了状态。
装饰器还可以嵌套使用,
@A
@B
@C
def f():
...
相当于:f = A(B(C(f)))
更多装饰器的例子:
例子1:
class tracer:
def __init__(self,func):
self.calls = 0
self.func = func
def __call__(self, *args):
self.calls += 1
print('call %s to %s' % (self.calls,self.func.__name__))
self.func(*args)
@tracer
def spam(a,b,c):
print(a + b + c)
spam(1,2,3)
执行过程:
@tracer语句-> class tracer:__init__; spam(1,2,3)函数调用 -> class tracer:__call__(xxxx)-> function spam(1,2,3)
例子2:
instance = {}
def getInstance(aClass, * args):
if aClass not in instance:
instance[aClass] = aClass(*args)
return instance[aClass]
def singleton(aClass):
def onCall(*args):
return getInstance(aClass, *args)
return onCall
@singleton
class Person:
def __init__(self,name):
self.name = name
def pay(self):
return 1000
bob = Person('bob')
print(bob.name,bob.pay())
sue = Person('Sue')
print(sue.name, sue.pay())
|
|