1.最简单的函数
'''示例1:最简单的函数,调用两次'''def f(): print('in f()')f()f()
运行结果:
in f()in f()
2.最简单函数,添加额外功能
'''示例2:最简单函数,添加功能:查看程序的执行时间'''import timedef f(): start = time.clock() print('in f()') end = time.clock() print('used time:', end - start)f()f()
运行结果:
in f()used time: 0.017538812265457945in f()used time: 0.007859906695771732
问题出现了,如果又想查看另一个函数的执行时间,怎么办?可以复制上述新增的代码到那个需要查看的函数中,但是这样做的话代码就可能会出现重复。下面的办法就避免了代码的重复。
3.定义新函数
''''示例3:定义一个函数timeit,将f引用传递给它,然后在timeit中调用f并计时。这样就不用每次想查看某个函数的执行时间,修改其函数定义了'''import timedef timeit(func): start = time.clock() func() end = time.clock() print('used time:', end - start)def f(): print('in f()')timeit(f)timeit(f)
运行结果:
in f()used time: 0.05688170348089686in f()used time: 0.0030139705110661524
这里还是有点问题:如果此前f函数在N出被调用,此时就不得不修改N处的调用代码。解决办法见下面的方法。
4.装饰器
不修改f函数的调用代码,但是想要在调用f时产生调用timeit(f)。
'''示例4:装饰函数f = timeit(f)'''import time# 定义一个计时器,传入一个函数,返回另一个附加了计时功能的函数def timeit(func): # 定义一个内嵌的包装函数,给传入的函数加上计时功能 def wrapper(): start = time.clock() func() end = time.clock() print('used time:', end - start) # 将包装后的函数返回 return wrapperdef f(): print('in f()')f = timeit(f)f()f()
运行结果:
in f()used time: 0.020904102006571737in f()used time: 0.003204015169534828
装饰器的作用:就是为已存在的的对象添加额外的功能。
5.使用@装饰函数
'''示例5:使用@装饰函数,相当于"f = timeit(f)"'''import timedef timeit(func): def wrapper(): start = time.clock() func() end = time.clock() print('used time:', end - start) return wrapper@timeitdef f(): print('in f()')f()f()
运行结果:
in f()used time: 0.026976211190267118in f()used time: 0.00859293609272234
6.内置装饰器
内置装饰器有3个:
(1)staticmethod:将类的实例方法变成静态方法
(2)classmethod:将类的实例方法变成类方法
(3)property:将类的实例方法变成类属性
'''示例6:静态方法和类方法的使用'''class MyClass(object): @staticmethod def smeth(): print('This is a static method') @classmethod def cmeth(cls): print('This is a class method of', cls)MyClass.smeth()MyClass.cmeth()m = MyClass()m.smeth()m.cmeth()
运行结果:
This is a static methodThis is a class method ofThis is a static methodThis is a class method of
7.functools模块
functools模块提供了2个装饰器
(1)wraps(wrapped[, assigned][, updated])
函数的特殊属性如函数名__file__,在被装饰后,函数名f会变成包装函数的名字wrapper。例如:在实例5的基础上添加一条打印__file__的语句:
'''示例5:使用@装饰函数,相当于"f = timeit(f)"'''import timedef timeit(func): def wrapper(): start = time.clock() func() end = time.clock() print('used time:', end - start) return wrapper@timeitdef f(): print('in f()')f()f()print(f.__name__)
运行结果:
in f()used time: 0.023279052418693102in f()used time: 0.004277017846773756wrapper
由结果可知:看到f.__name__的值是wrapper。
functools模块中的wraps装饰器可以解决这个问题,它能够将装饰过的函数的特殊属性保留。
例如:
'''示例7: functools.wraps装饰器'''import timeimport functoolsdef timeit(func): #"@functools.wraps(func)"等价于:"wrapper = functools.wraps(func)(wrapper)" @functools.wraps(func) def wrapper(): start = time.clock() func() end = time.clock() print('used time:', end - start) return wrapper#"@timeit"等价于:"f = timeit(f)"@timeitdef f(): print('in f()')f()f()print(f.__name__)
运行结果:
in f()used time: 0.009993350463016054in f()used time: 0.004484891854864229f
如果注释掉@functools.wraps(func)的结果:
in f()used time: 0.00913592083120428in f()used time: 0.004698438837834367wrapper
(2)total_ordering(cls)
这个装饰器在特定场合有一定的用处。它的作用是为了实现至少__lt__,__le__,__gt__,__ge__其中的一个类加上其他的比较方法,这是一个类的装饰器。具体查看其源码functools.py中的实现。
1 ################################################################################ 2 ### total_ordering class decorator 3 ################################################################################ 4 5 def total_ordering(cls): 6 """Class decorator that fills in missing ordering methods""" 7 convert = { 8 '__lt__': [('__gt__', lambda self, other: not (self < other or self == other)), 9 ('__le__', lambda self, other: self < other or self == other),10 ('__ge__', lambda self, other: not self < other)],11 '__le__': [('__ge__', lambda self, other: not self <= other or self == other),12 ('__lt__', lambda self, other: self <= other and not self == other),13 ('__gt__', lambda self, other: not self <= other)],14 '__gt__': [('__lt__', lambda self, other: not (self > other or self == other)),15 ('__ge__', lambda self, other: self > other or self == other),16 ('__le__', lambda self, other: not self > other)],17 '__ge__': [('__le__', lambda self, other: (not self >= other) or self == other),18 ('__gt__', lambda self, other: self >= other and not self == other),19 ('__lt__', lambda self, other: not self >= other)]20 }21 # Find user-defined comparisons (not those inherited from object).22 roots = [op for op in convert if getattr(cls, op, None) is not getattr(object, op, None)]23 if not roots:24 raise ValueError('must define at least one ordering operation: < > <= >=')25 root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__26 for opname, opfunc in convert[root]:27 if opname not in roots:28 opfunc.__name__ = opname29 opfunc.__doc__ = getattr(int, opname).__doc__30 setattr(cls, opname, opfunc)31 return cls