python 装饰器

来源:互联网 发布:如何删除知乎提问 编辑:程序博客网 时间:2024/05/22 06:42

Python装饰器学习(九步门):http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html

Python装饰器学习:http://blog.csdn.net/thy38/article/details/4471421

Python装饰器与面向切面编程:http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html

廖雪峰的官方网站
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819879946007bbf6ad052463ab18034f0254bf355000

Python 的闭包和装饰器:https://segmentfault.com/a/1190000004461404

装饰器就是对已有函数的进行的修饰,装饰器的功能是将被装饰的函数当作参数传递给与装饰器对应的函数(名称相同的函数),并返回包装后的被装饰的函数”

def deco(func):    print func    return func@decodef foo():passfoo()
<function foo at 0x0000000003A35048>
def deco_functionNeedDoc(func):    if func.__doc__==None:        print func,':','has no __doc__,its a bad habit'    else:        print func,':',func.__doc__    return  func@deco_functionNeedDocdef f():    print 'f() do someting'@deco_functionNeedDocdef g():    'I have a __doc__'    print 'g() do someting'f()g()
<function f at 0x0000000003A350B8> : has no __doc__,its a bad habit<function g at 0x00000000039ECF98> : I have a __doc__f() do sometingg() do someting

有参数装饰器

def decomaker(arg):    '通常对arg会有一定的要求'    def newDeco(func):        print func,arg        return func    return newDeco@decomakerdef foo():pass
'''示例2: 替换函数(装饰)装饰函数的参数是被装饰的函数对象,返回原函数对象装饰的实质语句: myfunc = deco(myfunc)'''def deco(func):    print func,'my func'    func()    return funcdef foo():    print 'I am foo'    return 'I am foo'foo_say=deco(foo)
<function foo at 0x0000000003A35208> my funcI am foo<function __main__.foo>
'''示例3: 使用语法糖@来装饰函数,相当于“myfunc = deco(myfunc)”但发现新函数只在第一次被调用,且原函数多调用了一次'''def deco(func):    print func,func.__doc__    return func@decodef foo():    'This is foo __doc__'    print 'I am foo'    return 'I am foo'for i in range(3):    foo()
<function foo at 0x0000000003AF1F28> This is foo __doc__I am fooI am fooI am foo
def deco(func):    def _deco(a,b):        print 'before'        he=func(a,b)        return he    return _deco@decodef foo(a,b):    print 'I am foo',a+b    return a+bfor i in range(3):    foo(3,5)
beforeI am foo 8beforeI am foo 8beforeI am foo 8

让我们回到刚开始的例子,在 deco 里面返回了一个 wrapper 函数对象。可以试着这么理解,deco的作用是给 func 进行装饰,wrapper 就是被装饰过的func。

怎么装饰 参数列表不一样 的多个函数?

def deco(func):    def wrapper(*args,**kwargs):        func(*args,**kwargs)        print "func is wraper"    return wrapper@decodef foo(x):    print 'In foo'    print 'foo have %s' %x@decodef foo1(x,y):    print 'In foo'    print 'foo have %s:%s' %(x,y)if __name__=='__main__':    foo('weiyudang')    foo1('weiyudang','160')    foo(range(10))    foo1(range(10),range(10,20))
In foofoo have weiyudangfunc is wraperIn foofoo have weiyudang:160func is wraperIn foofoo have [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]func is wraperIn foofoo have [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]func is wraper
#codeing:utf-8class locker:    def __init__(self):        print "this is class"    @staticmethod    def acquire():        print 'locker.acquire() called'def deco(cls):    def wrapper(func):        def __wrapper():            cls.acquire()        try:            return func        finally:            print 'final'        return __wrapper    return wrapper@deco(locker)def myfunc():    print 'This is not foo'myfunc()
finalThis is not foo
#codeing:utf-8import timeimport  randomdef jishi(func):    def deco(*args,**kwargs):        'This is deco'        start=time.clock()        func()        end=time.clock()        print 'use time:%f s'%(end-start)    return decodef shuoming(func):    def deco1(*args,**kwargs):        print func.__doc__        func()    return  deco1## 注意装饰器的顺序@shuoming@jishidef myfoo():    'This is test'    sum(range(100002))myfoo()print myfoo.__name__### 经过装饰之后函数的__name__属性发生变化,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错##Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:
This is decouse time:0.006677 sdeco1
import functoolsdef log(text):    print 0    def decorator(func):        print 1        @functools.wraps(func)        def wrapper(*args, **kw):            print '%s %s():' % (text, func.__name__)            return func(*args, **kw)        print 2        return wrapper    print 3    return decorator@log(u'执行')def foo(x):    print x    sum(range(100))    print range(3)foo('wwee')print foo.__name__
0312执行 foo():wwee[0, 1, 2]foo

使用__future__

Python的每个新版本都会增加一些新的功能,或者对原来的功能作一些改动。有些改动是不兼容旧版本的,也就是在当前版本运行正常的代码,到下一个版本运行就可能不正常了。

从Python 2.7到Python 3.x就有不兼容的一些改动,比如2.x里的字符串用’xxx’表示str,Unicode字符串用u’xxx’表示unicode,而在3.x中,所有字符串都被视为unicode,因此,写u’xxx’和’xxx’是完全一致的,而在2.x中以’xxx’表示的str就必须写成b’xxx’,以此表示“二进制字符串”。

要直接把代码升级到3.x是比较冒进的,因为有大量的改动需要测试。相反,可以在2.7版本中先在一部分代码中测试一些3.x的特性,如果没有问题,再移植到3.x不迟。

Python提供了future模块,把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中测试一些新版本的特性。举例说明如下:

为了适应Python 3.x的新的字符串的表示方法,在2.7版本的代码中,可以通过unicode_literals来使用Python 3.x的新的# still running on Python 2.7

from future import unicode_literals

print ‘\’xxx\’ is unicode?’, isinstance(‘xxx’, unicode)
print ‘u\’xxx\’ is unicode?’, isinstance(u’xxx’, unicode)
print ‘\’xxx\’ is str?’, isinstance(‘xxx’, str)
print ‘b\’xxx\’ is str?’, isinstance(b’xxx’, str)上面的代码仍然在Python 2.7下运行,但结果显示去掉前缀u的’a string’仍是一个unicode,而加上前缀b的b’a string’才变成了str:

$ python task.py'xxx' is unicode? Trueu'xxx' is unicode? True'xxx' is str? Falseb'xxx' is str? True

类似的情况还有除法运算。在Python 2.x中,对于除法有两种情况,如果是整数相除,结果仍是整数,余数会被扔掉,这种除法叫“地板除”:

10 / 3
3
要做精确除法,必须把其中一个数变成浮点数:

10.0 / 3
3.3333333333333335
而在Python 3.x中,所有的除法都是精确除法,地板除用//表示:

$ python3
Python 3.3.2 (default, Jan 22 2014, 09:54:40)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type “help”, “copyright”, “credits” or “license” for more information.

10 / 3
3.3333333333333335
10 // 3
3
如果你想在Python 2.7的代码中直接使用Python 3.x的除法,可以通过future模块的division实现:

from future import division

print ‘10 / 3 =’, 10 / 3
print ‘10.0 / 3 =’, 10.0 / 3
print ‘10 // 3 =’, 10 // 3
结果如下:

10 / 3 = 3.33333333333
10.0 / 3 = 3.33333333333
10 // 3 = 3
小结

由于Python是由社区推动的开源并且免费的开发语言,不受商业公司控制,因此,Python的改进往往比较激进,不兼容的情况时有发生。Python为了确保你能顺利过渡到新版本,特别提供了future模块,让你在旧的版本中试验新版本的一些特性。

偏函数

functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2

import functools#进制转换baseint('22',base=2)int2=functools.partial(int,base=2)int2('1001')9

所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:

0 0
原创粉丝点击