装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码边动的前提下增加额外的功能,装饰器返回值也是一个函数对象。简单来说,装饰器的作用就是为已经存在的对象添加额外的功能。
装饰器分为几种
简单装饰器:
def use_logging(func):
def wrapper(*args,**kwargs):
logging.warn("%s is running"% func.__name__)
return func(*args,**kwargs)
return wrapper
def bar():
print('I am bar')
bar = use_logging(bar)
bar()
函数use_logging就是装饰器,它把执行真正业务方法的func包裹在函数里面,看起来像bar被use_logging装饰了。在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。
@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作。
def use_logging(func):
def wrapper(*args,**kwargs):
logging.warn("%s is running"% func.__name__)
return func(*args,**kwargs)
return wrapper
@use_logging
def bar():
print('I am bar')
def foo():
print("I am foo")
bar()
如上所示,这样我们就可以省去bar = use_logging(bar)这一句了,直接调用bar()即可得到想要的结果。
带参数装饰器:
装饰器还有更大的灵活性,例如带参数的装饰器:在上面的装饰器调用中,比如@use_logging,该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。
def use_logging(level):
def decorator(func):
def wrapper(*args,**kwargs):
if level == "warn"
logging.warn("%s is running"% func.__name__)
return func(*args)
return wrapper
return decorator
@use_logging(level="warn")
def fool(name='foo'):
print('I am bar')
foo()
上面的use_logging是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当我 们使用@use_logging(level=”warn”)调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。
类装饰器:
再来看看类装饰器,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')
@Foo
def bar():
print ('bar')
bar()
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、name、参数列表
内置装饰器:
@staticmathod、@classmethod、@property
装饰器的顺序
@a
@b
@c
def f ():
等效于
f = a(b(c(f)))
AssertionError:当assert断言条件为假的时候抛出的异常
AttributeError:当访问的对象属性不存在的时候抛出的异常
IndexError:超出对象索引的范围时抛出的异常
KeyError:在字典中查找一个不存在的key抛出的异常
NameError:访问一个不存在的变量时抛出的异常
OSError:操作系统产生的异常
SyntaxError:语法错误时会抛出此异常
TypeError:类型错误,通常是不通类型之间的操作会出现此异常
ZeroDivisionError:进行数学运算时除数为0时会出现此异常
IndentationError:缩进错误
示例:
try:
正常的操作
......................
except(Exception1[, Exception2[,...ExceptionN]]]):
发生以上多个异常中的一个,执行这块代码
......................
else:
如果没有异常执行这块代码
如果一个函数有多个错误,则从上往下执行,如果执行错误,则报错,后面另外的错误不会执行。
1、编写自己的异常时,通常是继承Exception
2、如果继承的是BaseException,那么就不会被通用的except Exception捕捉到
3、自己定义的异常Python不会自动触发,需要自己触发,用raise进行触发
4、python只会自动触发它自己本身内置的异常,如IndexEerror,NameError,IOError等,只要是Error结尾通常都是内置异常
class MyException(Exception):
def __init__(self, msg): #msg参数用于接收自己触发异常时传进来的错误描述信息
self.msg = msg
def __str__(self): #格式化输出
return "[Internal Logic Error:] %s" % (self.msg)
if __name__ == '__main__':
flag = False
try:
if flag:
print("Initialization data")
print("done...")
else:
raise MyException("no data") #触发自己的异常
except MyException as err: #捕捉被触发的自定义异常
print(err) #打印异常信息,如果有参数,那么可通过err.args打印参数
finally:无论try是否抛出异常,永远执行finally后代码
try:
...................
finally:
..................