您的位置:首页 > 编程语言 > Python开发

python 装饰器

2016-06-29 21:15 691 查看
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
@deco
def foo():pass
foo()


<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_functionNeedDoc
def f():
print 'f() do someting'

@deco_functionNeedDoc
def 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 someting
g() do someting


有参数装饰器

def decomaker(arg):
'通常对arg会有一定的要求'
def newDeco(func):
print func,arg
return func
return newDeco

@decomaker
def foo():pass


'''示例2: 替换函数(装饰)
装饰函数的参数是被装饰的函数对象,返回原函数对象
装饰的实质语句: myfunc = deco(myfunc)'''
def deco(func):
print func,'my func'
func()
return func
def foo():
print 'I am foo'
return 'I am foo'

foo_say=deco(foo)


<function foo at 0x0000000003A35208> my func
I am foo

<function __main__.foo>


'''示例3: 使用语法糖@来装饰函数,相当于“myfunc = deco(myfunc)”
但发现新函数只在第一次被调用,且原函数多调用了一次'''
def deco(func):
print func,func.__doc__
return func

@deco
def 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 foo
I am foo
I am foo


def deco(func):
def _deco(a,b):
print 'before'
he=func(a,b)
return he
return _deco
@deco
def foo(a,b):
print 'I am foo',a+b
return a+b

for i in range(3):
foo(3,5)


before
I am foo 8
before
I am foo 8
before
I 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

@deco
def foo(x):
print 'In foo'
print 'foo have %s' %x

@deco
def 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 foo
foo have weiyudang
func is wraper
In foo
foo have weiyudang:160
func is wraper
In foo
foo have [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
func is wraper
In foo
foo 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-8
class 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()


final
This is not foo


#codeing:utf-8

import time
import  random
def jishi(func):
def deco(*args,**kwargs):
'This is deco'
start=time.clock()
func()
end=time.clock()
print 'use time:%f s'%(end-start)
return deco

def shuoming(func):
def deco1(*args,**kwargs):
print func.__doc__
func()
return  deco1

## 注意装饰器的顺序
@shuoming
@jishi

def myfoo():
'This is test'
sum(range(100002))

myfoo()
print myfoo.__name__
### 经过装饰之后函数的__name__属性发生变化,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错
##Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:


This is deco
use time:0.006677 s
deco1


import functools
def 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__


0
3
1
2
执行 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? True
u'xxx' is unicode? True
'xxx' is str? False
b'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
#进制转换base
int('22',base=2)
int2=functools.partial(int,base=2)
int2('1001')
9


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

注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: