Python 装饰器
取得成就时坚持不懈,要比遭到失败时顽强不屈更重要。——拉罗什夫科
- python 装饰器(function decorators) 就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给新函数增加新的功能
装饰器概念的引入
一般而言, 我们想要拓展原来的函数,最直接的办法就是侵入代码里修改
- 这是最初始的函数
import time
def f():
print('hello')
time.sleep(1)
print('world')
- 这个时候我们想记录下这个函数执行的总时间,最简单的做法就是改动原先的代码
import time
def f():
start_time = time.time()
print('hello')
time.sleep(1)
print('world')
end_time = time.time()
execution_time = (end_time-start_time)*1000
print('time is {0} s starttime is {1} endtime is {2}'.format(execution_time ,start_time,end_time))
- 但是实际情况是,有些时候核心代码并不能直接修改,所以在不修改源代码的情况下,我们可以在定义一个函数(但是生效的时候需要再次执行函数)
import time
def f():
print('hello')
time.sleep(1)
print('world')
def deco(f):
start_time = time.time()
f() #执行核心函数
end_time = time.time()
execution_time = (end_time-start_time)*1000
print('time is {0} s starttime is {1} endtime is {2}'.format(execution_time ,start_time,end_time))
deco(f) # 调用函数
这里我们定义了一个函数 deco, 它的参数是一个函数,然后这个参数嵌入了计时功能,但是想要拓展一亿个函数功能,就是要执行一亿次 deco 函数,所以这样不理想.于是装饰器的概念就出来了
装饰器的符号和使用
装饰器一般用@符号写在核心函数的前面
import time
def deco(f):
def wrapper():
start_time = time.time()
f() # 执行核心函数
end_time = time.time()
execution_time = (end_time-start_time)*1000
print('time is {0} s starttime is {1} endtime is {2}'.format(
execution_time, start_time, end_time))
return wrapper
@deco
def f():
print('Hello')
time.sleep(1)
print('World!')
f()
这里的 deco 函数就是最原始的装饰器,他的参数是一个函数,返回值也是一个函数其中作为参数的这个函数 f()就在返回函数 wrapper()的内部执行.然后再函数 f()前面加上@deco,f()函数就相当于被注入了计时功能,现在只要调用 f(),它就已经变身为’新的功能更多’的函数了
使用多个装饰器,装饰一个函数
import time
def deco01(f):
def wrapper(*args, **kwargs):
print("this is deco01")
start_time = time.time()
f(*args, **kwargs)
end_time = time.time()
execution_time = (end_time - start_time)*1000
print("time is %d ms" % execution_time)
print("deco01 end here")
return wrapper
def deco02(f):
def wrapper(*args, **kwargs):
print("this is deco02")
f(*args, **kwargs)
print("deco02 end here")
return wrapper
@deco01
@deco02
def f(a,b):
print("be on")
time.sleep(1)
print("result is %d" %(a+b))
f(3,4)
装饰器调用顺序
装饰器是可以叠加使用的,对于 Python 中的@语法糖,装饰器的调用顺序与使用@语法糖声明的顺序是相反的。在这个例子中’f(3,4)=deco01(deco02(f(3,4)))’
Python 内置装饰器
在 Python 中有三个内置的装饰器,都是和 class 有关 staticmethod,classmethod 和 property
staticmethod 是类静态方法其跟成员的方法区别就是没有 self 参数,并且可以在类不进行实例化的情况下调用
classmethod 与成员方法的区别在于它所接收的第一个参数不是 self(类实例化指针)而是 cls(当前类的具体类型)
property 是属性的意思。标识可以通过类实例直接访问的信息
class Foo(obj):
def __init__(self,var):
super(Foo,self).__init__()
self._var = var
@property
def var(self):
return self._var
@var.setter
def var(self,var):
self._var = var
foo = Foo('var 1')
print(foo.var)
foo.var = 'var 2'
print foo.var