无聊之人--除了技术,还是技术,你懂得
分类: Python/Ruby
2013-08-14 21:06:36
'''示例1:最简单的函数,调用两次''' def f(): print('in f()') f() f()
运行结果:
in f() in f()
2.最简单函数,添加额外功能
'''示例2:最简单函数,添加功能:查看程序的执行时间''' import time def f(): start = time.clock() print('in f()') end = time.clock() print('used time:', end - start) f() f()
运行结果:
in f() used time: 0.017538812265457945 in f() used time: 0.007859906695771732
问题出现了,如果又想查看另一个函数的执行时间,怎么办?可以复制上述新增的代码到那个需要查看的函数中,但是这样做的话代码就可能会出现重复。下面的办法就避免了代码的重复。
3.定义新函数
''''示例3:定义一个函数timeit,将f引用传递给它,然后在timeit中调用f并计时。 这样就不用每次想查看某个函数的执行时间,修改其函数定义了''' import time def 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.05688170348089686 in 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 wrapper def f(): print('in f()') f = timeit(f) f() f()
运行结果:
in f() used time: 0.020904102006571737 in f() used time: 0.003204015169534828
装饰器的作用:就是为已存在的的对象添加额外的功能。
5.使用@装饰函数
'''示例5:使用@装饰函数,相当于"f = timeit(f)"''' import time def timeit(func): def wrapper(): start = time.clock() func() end = time.clock() print('used time:', end - start) return wrapper @timeit def f(): print('in f()') f() f()
运行结果:
in f() used time: 0.026976211190267118 in 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 method This is a class method of <class '__main__.MyClass'> This is a static method This is a class method of <class '__main__.MyClass'>
7.functools模块
functools模块提供了2个装饰器
(1)wraps(wrapped[, assigned][, updated])
函数的特殊属性如函数名__file__,在被装饰后,函数名f会变成包装函数的名字wrapper。例如:在实例5的基础上添加一条打印__file__的语句:
'''示例5:使用@装饰函数,相当于"f = timeit(f)"''' import time def timeit(func): def wrapper(): start = time.clock() func() end = time.clock() print('used time:', end - start) return wrapper @timeit def f(): print('in f()') f() f() print(f.__name__)
运行结果:
in f() used time: 0.023279052418693102 in f() used time: 0.004277017846773756 wrapper
由结果可知:看到f.__name__的值是wrapper。
functools模块中的wraps装饰器可以解决这个问题,它能够将装饰过的函数的特殊属性保留。
例如:
'''示例7: functools.wraps装饰器''' import time import functools def 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)" @timeit def f(): print('in f()') f() f() print(f.__name__)
运行结果:
in f() used time: 0.009993350463016054 in f() used time: 0.004484891854864229 f
如果注释掉@functools.wraps(func)的结果:
in f() used time: 0.00913592083120428 in f() used time: 0.004698438837834367 wrapper
(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__ = opname 29 opfunc.__doc__ = getattr(int, opname).__doc__ 30 setattr(cls, opname, opfunc) 31 return cls