Python的装饰器@----转载自azhao_dn

前段时间在看一些有关python web framwork的时候,发现在python语言里竟然有“@”符号,一查资料,原来是python装饰器(python装饰器也可以通过除了“@”的其他语法进行定义)。装饰器,是一种设计模式,用于动态地给对象添加行为,之前的一篇文章也提到过。python中也有装饰器,不过和普遍意义上的装饰器不同,python中的装饰器实际上是一种“语法糖”,是一种语句的简便写法。比如,a[idx]就是*(a+idx)的一种简便写法,也算是一种语法糖。 假设有如下写法:

1
2
3
@dec
def  func():
   pass

它等同于:

 

1
func  =  dec(func)

dec也是一个函数,只不过这个函数比较特殊,它的参数是一个函数(就是原先被装饰的函数func),它的返回值是一个函数。这样,再运行func()时,就是运行经过“装饰”的函数了。 python decorator可以帮助我们轻松地为函数或者类添加行为,而不用像普通的装饰器模式那样基于某个接口,大概这也算是动态语言的优势之一吧。 好,来看一些例子。

面向切面的编程

当我们要对许多函数进行相同的测试或者进行其他处理的时候,如果在每个函数都写一遍的话,代码太过重复,不利于统一管理。我们可以写一些统一的函数,然后在需要进行处理的函数前面加上decorator就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def  before(f):
     def  wrapper():
         print  'before function'
         f()
     return  wrapper
 
def  after(f):
     def  wrapper():
         f()
         print  'after function'
     return  wrapper
 
@before
@after
def  func():
     print  'this is function'
 
if  __name__  = =  '__main__' :
     func()

这样,就可以在函数前后进行相应的处理了。程序输出如下:

before function

this is function

after function

Singleton模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def  singleton( cls ):
     instances  =  {}
     def  wrapper():
         if  cls  not  in  instances:
             instances[ cls =  cls ()
         return  instances[ cls ]
     return  wrapper
 
@singleton
class  MyClass:
     def  __init__( self ):
         self .num  =  0
 
if  __name__  = =  '__main__' :
     c1  =  MyClass()
     print  c1.num
     c2  =  MyClass()
     c2.num  =  1
     print  c1.num
     print  (c1  = =  c2)

这样,每次“新建”MyClass类型,得到的都会是同一个实例。程序输出如下:

0

1

True

检验函数参数和返回值的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def  accepts( * types):
     def  check_args(f):
         #若去掉该断言,则代码可正常运行
         assert  len (types)  = =  f.func_code.co_argcount,  'type len: %d args len: %d'  % ( len (types), f.func_code.co_argcount)
         def  new_f( * args,  * * kwds):
             for  (a, t)  in  zip (args, types):
                 assert  isinstance (a, t),  'arg %r does not match %s'  %  (a, t)
             return  f( * args,  * * kwds)
         new_f.func_name  =  f.func_name    # why?
         return  new_f
     return  check_args
 
def  returns(rtype):
     def  check_ret(f):
         def  new_f( * args,  * * kwds):
             ret  =  f( * args,  * * kwds)
             assert  isinstance (ret, rtype),  'return value %r does not match %s'  % (ret, rtype)
             return  ret
         new_f.func_name  =  f.func_name
         return  new_f
     return  check_ret
 
@returns (( int float ))
@accepts ( int , ( int float ))
def  func(arg1, arg2):
     return  arg1  +  arg2
 
if  __name__  = =  '__main__' :
     print  func( 1 2.0 )
     print  func( '1' '2' )

在这段代码中,accepts函数用来保证被装饰的函数有两个参数,第一个参数为int型,第二个参数为int或float型,returns函数保证返回值为int或float型。那么,运行func(1, 2.0),assert就能通过,而func(’1′, ’2′)就不能通过。

Todo:这里还有一个问题,就是当@returns和@accepts语句交换顺序之后,accepts中检测函数参数个数的assert就无法通过,输出参数个数为0,还不知道是什么原因,待解决。

若去掉check_args函数中的对于f的参数个数的assert判断,则returns和accepts两个decorator无论什么顺序,代码均可正常运行。是由于new_f(*args, **kwds)改变了实际传入的参数的个数?

参考资料:

个人理解:
装饰器就是一个函数,这个函数的参数就是被装饰的函数指针,装饰器返回一个内嵌包裹函数的函数指针,在这个包裹函数中,装饰器修改了被装饰函数的行为,并返回被装饰的函数,并且包裹函数和被装饰的函数都采用列表参数。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值