由函数计时器引发的思考

由于需要对算法进行计时,所以要引入计时来计算函数运行时间。
由此搜索到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)。与传统编程习惯的从上往下执行方式相比较而言,像是在函数执行的流程中横向地插入了一段逻辑。在特定的业务领域里,能减少大量重复代码。较为经典的有插入日志、性能测试、事务处理等。面向切面有装饰器模式和代理模式。

装饰器模式,代理模式区别:

代理模式中,代理类对被代理的对象有控制权,决定其执行或者不执行。而装饰模式中,装饰类对代理对象没有控制权,只能为其增加一层装饰,以加强被装饰对象的功能,仅此而已。
什么情况下用代理模式什么情况下用装饰模式呢?那就得看情况了,如果是为了给对象增加功能,那就用装饰模式。 。

java中AOP(面向切面编程)的实现是建立在CGLib提供的类代理(静态代理,动态代理【反射】)和jdk提供的接口代理,IOC(控制反转)的实现建立在工厂模式、java反射机制和jdk的操作XML的DOM解析方式(配置文件).
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值