1.最简单的函数

'''示例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

 

 

 

posted on 2013-05-16 12:44  101010  阅读(460)  评论(0编辑  收藏  举报