码迷,mamicode.com
首页 > 编程语言 > 详细

python学习笔记-Day04-第四部分(装饰器)

时间:2015-11-21 22:54:15      阅读:380      评论:0      收藏:0      [点我收藏+]

标签:python   装饰器   

这周学到了python的装饰器,以前没有接触过,问了一个搞php开发的同事什么是装饰器,他说就好像构造函数一样,可惜我已经把构造函数忘得光光了,想不起来是啥了。现在就找资料了解了解。毕竟装饰器是一个不用也能实现程序的功能,但是用了装饰器以后会显得你的技术特NB,但是不太好理解


学装饰器之前,需要先了解一下函数,前面的笔记里,有写过函数相关的笔记,可以先去参考一下前面的文章,这里只简单说一下。

在python中,函数由  def 关键字,函数名,可选的参数列表和函数体 来组成,通过return语句来返回值,如果没有return语句的时候,函数自动返回一个None值,



装饰器其实就是把一个函数当做参数,然后返回一个替代版的函数,

def wrapper(a_fun):
    def fun():
        print "a fun"
        tmp = a_fun()
        return tmp +1
    return fun

def w_test():
    return 1

var1 = wrapper(w_test)
print var1()   #1
print w_test()

输出:

a fun   # var1() 输出
2         #  var1() 输出
1         # w_test() 输出


上面是一个装饰器的例子,我们定义了一个函数 wrapper() ,参数为一个名叫a_fun的函数,在函数内部定义了一个嵌套的函数 fun() 。fun() 会输出一串字符串,然后调用 a_fun(), tmp 可以得到a_fun()的返回值, wrapper每次调用 fun() 的时候值可能会不一样(如果使用的是其他函数),但是不管a_fun()的返回值 是什么,外面都会调用它,最后 fun() 的返回值为 a_fun()+1 。 在位置 #1处,我们调用存储在变量var1 里面的函数,可以得到打印出的字符串和返回值 2,而不是函数 w_test() 的返回值


我们可以认为 var1 是函数  w_test() 的一个装饰版本,或者说一个改造版本,而且并没有对原来的函数w_test() 进行任何改变。 写一个装饰器的话,外面可以用装饰版本 完全替换掉原来的函数w_test(),这样就可以得到一个 改造版 的函数w_test() , 在使用过程中 ,还不需要学习新的语法,只要简单的给变量复制就可以达到效果


w_test = wrapper(w_test)
w_test 
输出:
<function fun at 0x7f5edf6c5668>

执行上面的代码后,外面再怎么调用都不会牵扯原来的函数w_test(),调用的会是改造版本的w_test()


再来一个具体的例子.

wrapper(func):
    result():
        func()
        result
foo():
    foo = wrapper(foo)   ### 这里
foo()



使用 @ 标识符 将装饰器应用到函数

python2.4 支持使用标识符讲装饰器应用到函数上,只需要在函数的定义钱叫上@和装饰器的名称,

上面的例子中,外面使用的方法是

foo = wrapper(foo)

这种方法可以在任何时候对任意的方法进行包装,但是代码写的多,累啊。我们可以使用简单的方法,使用@装饰,将上面的例子修改后:

wrapper(func):
    result():
        func()
        result

@foo():
    foo()

需要记住的是, 使用  foo = wrapper(foo)  和在函数前加 @wrapper  这两种方法是一样的,python只是增加了一些语法糖 ,让装饰的行为更加直接明确和优雅,说白了 就是让你更容易看代码。


关于传递参数

上面我们已经完成了一个装饰器,但是这个装饰器只能应用在一类具体的方法上。如果我们想要实现一个能够应用在任何方法的装饰器上要怎么做呢?

其实可以猜出来一部分 使用*args 和 **kwargs。

例:

first(*args):
    args

first()
first(,,)
lst = [,,,]
first(*lst)

上面定义了函数 first ,将任何传递进来的参数打印, * 表示 调用的方法的时候,额外的参数可以从一个可迭代的列表中获得,或者是 定义方法的时候 表示这个参数可以接收任意数量的位置参数


** 比* 稍微复杂一点点, 使用**的时候,表示与其对应的是一个代表着键值对的参数字典。

例:

sec(**kwargs):
    kwargs

dic = {:,:}
sec()
sec(=,=)
sec(**dic)


让我们来写一个功能更强大的装饰器

war(func):
    in_war(*args,**kwargs):
        %(args,kwargs)
        
    in_war


@foo_1(x,y=):
    x+y

@foo_2():
    foo_1(,)
foo_1()
foo_2()


http://timesnotes.blog.51cto.com/1079212/1715330

http://www.timesnotes.com/?p=111


本文出自 “Will的笔记” 博客,请务必保留此出处http://timesnotes.blog.51cto.com/1079212/1715330

python学习笔记-Day04-第四部分(装饰器)

标签:python   装饰器   

原文地址:http://timesnotes.blog.51cto.com/1079212/1715330

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!