python装饰器高级用法
1.装饰类
下面,直接来看代码是如何实现装饰类的:
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的次数了
2.装饰器捕捉异常
有一个check类,其中有方法read_value()。由于某些原因,方法read_value有可能抛出异常而使程序崩溃,所以需要对整个方法做try....except处理,如:
没有捕捉异常之前:
class check(object): def __init__(self): pass def receive(self): print('receive from exception.') def read_value(self): print('here i will do something') 'a' + 1 # 这里会报异常 c = check() c.read_value()
加了try....except捕捉异常后:
class check(object): def __init__(self): pass def receive(self): print('receive from exception.') def read_value(self): try: print('here i will do something') 'a' + 1 except Exception as e: print(e) c = check() c.read_value()
虽然程序不会报出异常,但这样处理,有些丑陋。来看看装饰器是如何处理的:
def catch_exception(func): def wrapper(*args,**kwargs): try: u = func(*args,**kwargs) return u except Exception: return 'an exception raised' return wrapper class check(object): def __init__(self): pass def receive(self): print('receive from exception.') @catch_exception def read_value(self): print('here i will do something') 'a' + 1 c = check() c.read_value()
很好,使用装饰器,来装饰函数,这样使我们的代码更加pythonic。但是,如果程序报出异常后,调用类中的另外一个方法,那怎么办?很简单,给装饰器加上一个参数self:
def catch_exception(func): def wrapper(self,*args,**kwargs): try: u = func(self,*args,**kwargs) return u except Exception: self.receive() return 'an exception raised' return wrapper class check(object): def __init__(self): pass def receive(self): print('receive from exception.') @catch_exception def read_value(self): print('here i will do something') 'a' + 1 c = check() c.read_value()
有木有感觉,很神奇。
3.装饰器注意事项
3.1函数的属性会发生变化
装饰器动态创建的新函数替换原来的函数,但是,新函数缺少很多原函数的属性,如docstring和名字。