由于需要对算法进行计时,所以要引入计时来计算函数运行时间。
由此搜索到time模块的clock方法:
time
import time
def func():
sleep(0.1)
start = time.clock()
func()
end = time.clock()
time = start - end
print time
运行结果:
>>> 0.000816
输出结果是不符合我们的预期的。查看time的帮助发现time模块有两种方法返回系统时钟:
Functions:
time() -- return current time in seconds since the Epoch as a float
clock() -- return CPU time since process start as a float
time.clock()返回的当前处理器的时间,而linux/unix平台与win平台对系统时钟的实现不同,*nix返回处理器时间,而windows返回第一次调用这个函数的时间。
time.time()返回的是UTC时间。
因此在*nix系统中使用time()的精确率比较高,而在window下clock()比较精确。
如果我们需要一份代码在多平台上选择最精却的计时怎么办呢?
timeit
timeit
模块的timeit.default_time()
方法即可根据当前的系统平台选择最精确的时钟。
你也可以使用timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
来计算一个的算法的时间。
参数分别是 stmt(需要测量的语句或函数),setup(初始化代码或构建环境的导入语句),timer(计时函数),number(每一次测量中语句被执行的次数)。注:由于 timeit() 正在执行语句,语句中如果存在返回值的话会阻止 timeit() 返回执行时间。timeit() 会取代原语句中的返回值。
可是无论是第一种方法还是timeit()方法,每一次测试一个算法都要繁琐地加入一些其他的代码。有没有一种比较简介方便的方式呢?
import time
def calc_time(fn):
def _wrapper(*args, **kwargs):
start = time.time()
fn(*args, **kwargs)
print "%s cost %s second" % (fn.__name__,str(time.time()-start)),"second"
return _wrapper
def func():
sleep(0.1)
func = calctime(func)
func()
其实这个就是装饰器func被calc_time装饰了。
python的额外支持-装饰器(@decoration)
import time
def calc_time(fn):
def _wrapper(*args, **kwargs):
start = time.time()
fn(*args, **kwargs)
print "%s cost %s second" % (fn.__name__,str(time.time()-start)),"second"
return _wrapper
@calc_time()
def func():
sleep(0.1)
这样每一次调用算法就会自动输出时间了
>>>func()
>>>func cost 0.1 second
这是最简单的装饰器,但是函数的特殊属性比如函数名func.__name__
,在被装饰后就会被改变成wrapper
,如果你希望使用反射,可能会导致意外的结果。装饰器functools.wraps
可以解决这个问题。
functools模块
wraps(wrapped[, assigned][, updated]):
代码示例
import time
import functools
def calc_time(fn):
@functools.wrap(fn)
def _wrapper(*args, **kwargs):
start = time.time()
fn(*args, **kwargs)
print "%s cost %s second" % (fn.__name__,str(time.time()-start)),"second"
return _wrapper
@calc_time()
def func():
sleep(0.1)
这样func.__name__
依然是func
而不是wrapper
。
wrap
还有两个可选的参数,assigned中的属性名将使用赋值的方式替换,而updated中的属性名将使用update的方式合并。
对于这个装饰器,相当于wrapper = functools.wraps(func)(wrapper)
先挖个坑(日后再填)
面向切面编程(编程思想)
这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。与传统编程习惯的从上往下执行方式相比较而言,像是在函数执行的流程中横向地插入了一段逻辑。在特定的业务领域里,能减少大量重复代码。较为经典的有插入日志、性能测试、事务处理等。面向切面有装饰器模式和代理模式。
装饰器模式,代理模式区别:
代理模式中,代理类对被代理的对象有控制权,决定其执行或者不执行。而装饰模式中,装饰类对代理对象没有控制权,只能为其增加一层装饰,以加强被装饰对象的功能,仅此而已。
什么情况下用代理模式什么情况下用装饰模式呢?那就得看情况了,如果是为了给对象增加功能,那就用装饰模式。 。