Python札记 -- 装饰器

这几天花了点时间了解了下 Python的装饰器。其实以前在书上也看过有关的内容,不过当时不理解。今天把自己的一点体会写出来跟大家分享一下。

网上流传得比较广的,有关 python装饰器的文章有两篇,一篇是 CSDN上的,另外一篇是园子里的。附带链接如下:
    http://blog.csdn.net/thy38/article/details/4471421
    http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html
    我个人比较喜欢园子里的那篇,讲得很透彻,能让大家对装饰器有个大概的了解。至于 CSDN那篇,我不太清楚他的python版本,他给出来的 “装饰器语法-- 无参数装饰器 ” 在我的机器上运行时是有问题的,稍后我会详细跟大家讨论。

一、装饰器能干啥?

正如 AstralWind 在他的博客中介绍, “装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。 ”

二、如何编写自己的装饰器?

让我们来编写一个比较简单的装饰器,在 Python里面代码看起来会是这样的:

1 #!/usr/bin/env python

2

3 def deco(func):

4      def wrapper( ):

5          print "Wrap start"

6          func()

7          print "Wrap end\n"

8      return wrapper

9

10 @deco

11 def foo():

12      print "In foo():"

13

14 foo()

运行起来是这个样子的:

1 $ python decorate.py

2 Wrap start

3 In foo():

4 Wrap end

我们可以在“Wrap start” 和“Wrap end”里面做一些自己想要的功能,比如计算运行时间,输出日志等等。

三、为什么要返回一个函数?

我第一次看到“return wrapper”这句的时候,就在想为什么要返回一个函数? 返回函数是也为了赋值给变量

正好 CSDN上的文章是没返回函数的,让我们来仔细分析一下代码:

1 def deco(func):

2      print func

3      return func

4 @deco

5 def foo(): pass

6

7 foo()

运行的结果看起来很完美,但是只是看起来。让我们把代码修改一下:

1 >>> def deco(func):

2 ...     print "In deco"

3 ...     return func

4 ...

5 >>> @deco

6 ... def foo():

7 ...     print "In foo"

8 ...

9 In deco

10 >>>

等等,代码里面还没有调用 foo(),怎么就print “In deco” 了?

这里编写的装饰器根本就没有达到我们要求的功能,因为它返回的还是 func 本身,print “In deco” 也只会在初始化的时候运行一次,仅仅一次。
    让我们回到刚开始的例子,在 deco 里面返回了一个 wrapper 函数对象。可以试着这么理解, deco的作用是给 func 进行装饰, wrapper 就是被装饰过的func。

然后我们就可以重复调用这个被装饰过的函数。

四、怎么装饰一个 需要传参数 的函数?

现在另一个问题又来了,前面被装饰的函数都是不带参数的,那带参数的函数要怎么装饰呢?

让我们先尝试下前面的办法:

1 >>> def deco(func):

2 ...     def wrapper():

3 ...         print "Wrap start"

4 ...         func()

5 ...         print "Wrap end\n"

6 ...     return wrapper

7 ...

8 >>> @deco

9 ... def foo(x):

10 ...     print "In foo():"

11 ...     print "I have a para: %s" % x

12 ...

13 >>> foo(‘x‘)

14 Traceback (most recent call last):

15    File "<stdin>", line 1, in <module>

16 TypeError: wrapper() takes no arguments (1 given)

报了个缺少参数的错误,那把这个参数带上:

1 >>> def deco(func):

2 ...     def wrapper(x):

3 ...         print "Wrap start"

4 ...         func(x)

5 ...         print "Wrap end\n"

6 ...     return wrapper

7 ...

8 >>> @deco

9 ... def foo(x):

10 ...     print "In foo():"

11 ...     print "I have a para: %s" % x

12 ...

13 >>> foo(‘x‘)

14 Wrap start

15 In foo():

16 I have a para: x

17 Wrap end

现在可以正常传递参数了。

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

继续发散一下,要是想装饰多个函数,但是这些函数的参数列表变化很大的呢?
    这个时候,就到了使用Python参数魔法的时候了。
    定义函数时:*params:收集其余的位置参数,返回元组。     **params:收集其余的关键字参数,返回字典。
    调用函数时:*params:将元组拆分为位置参数传入。     **params:将字典拆分为关键字参数传入。

利用上面的参数魔法后,代码看起来会是这样的:

1 #!/usr/bin/env python

2

3 def deco(func):

4      def wrapper(*args, ** kwargs):

5          print "Wrap start"

6          func(*args, ** kwargs)

7          print "Wrap end\n"

8      return wrapper

9

10 @deco

11 def foo(x):

12      print "In foo():"

13      print "I have a para: %s" % x

14

15 @deco

16 def bar(x,y):

17      print "In bar():"

18      print "I have two para: %s and %s" % (x, y)

19

20 @deco

21 def foo_dict(x,z= ‘dict_para‘):

22      print "In foo_dict:"

23      print "I have two para, %s and %s" % (x, z)

24

25 if __name__ == "__main__" :

26      foo(‘x‘)

27      bar(‘x‘, ‘y‘)

28      foo_dict(‘x‘, z= ‘dict_para‘)

运行一下看看效果:

1 $ python decorate.py

2 Wrap start

3 In foo():

4 I have a para: x

5 Wrap end

6

7 Wrap start

8 In bar():

9 I have two para: x and y

10 Wrap end

11

12 Wrap start

13 In foo_dict:

14 I have two para, x and dict_para

15 Wrap end

本人水平有限,以上如有错误,欢迎指正,谢谢大家 ^_^。

来自为知笔记(Wiz)

时间: 2024-11-06 07:09:05

Python札记 -- 装饰器的相关文章

Python札记 -- 装饰器补充

本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: 1 #!/usr/bin/env python 2 3 def deco(func): 4 def wrapper(): 5 print "Wrap start" 6 func() 7 print "Wrap end\n" 8 return wrapper 9 10 @deco 11 def foo(): 12 """Do

尝试自己的Perl语言的包 TCP协议的再包装起到类似python语言装饰器的效果

#!/usr/bin/perl # Filename: BuildSocketTCP.pm # #   Copyright 2012 Axxeo GmbH #   Licensed under the Apache License, Version 2.0 (the "License"); #   you may not use this file except in compliance with the License. #   You may obtain a copy of t

尝试自己的Perl语言的包 UDP协议的再包装起到类似python语言装饰器的效果

#!/usr/bin/perl # Filename: BuildSocketUDP.pm # #   Copyright 2012 Axxeo GmbH #   Licensed under the Apache License, Version 2.0 (the "License"); #   you may not use this file except in compliance with the License. #   You may obtain a copy of t

python函数装饰器

学习装饰器前提需要了解高阶函数,函数嵌套,函数闭包 python函数装饰器,顾名思义就是装饰函数,为函数添加新功能的的一种方式. 为什么要使用装饰器呢? 因为函数在运行时,如果不使用装饰器对函数进行功能添加,需要修改函数源代码,这样修改无疑会增加程序的冗余和复杂性,也不便于程序员对其进行修改.使用装饰器,可以在不改变函数源代码和调用方式的前提下,使用语法糖@装饰器,对函数功能进行添加. 装饰器本质上就是一个函数. 我们使用一个简单的例子来实现: import time #这是一个装饰器函数名为t

Python之装饰器、迭代器和生成器

在学习python的时候,三大“名器”对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器.迭代器和生成器理解进行解释. 为什么要使用装饰器 什么是装饰器?“装饰”从字面意思来谁就是对特定的建筑物内按照一定的思路和风格进行美化的一种行为,所谓“器”就是工具,对于python来说装饰器就是能够在不修改原始的代码情况下给其添加新的功能,比如一款软件上线之后,我们需要在不修改源代码和不修改被调用的方式的情况下还能为期添加新的功能,在python种就可以用装饰器来实现,同样在写

python之装饰器 实例

=====================================写法1========================== import time def timer(func):     def deco():         start_time = time.time()         func()         stop_time = time.time()         print('the func run time is %s' %(stop_time - star

【转】详解Python的装饰器

原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def say_hello(): print "hello!" def say_goodbye(): print "hello!" # bug here if __name__ == '__main__':

如何用python的装饰器定义一个像C++一样的强类型函数

Python作为一个动态的脚本语言,其函数在定义时是不需要指出参数的类型,也不需要指出函数是否有返回值.本文将介绍如何使用python的装饰器来定义一个像C++那样的强类型函数.接下去,先介绍python3中关于函数的定义. 0. python3中的函数定义 举个例子来说吧,比如如下的函数定义: 1 def fun(a:int, b=1, *c, d, e=2, **f) -> str: 2 pass 这里主要是说几点与python2中不同的点. 1)分号后面表示参数的annotation,这个

Python 函数装饰器入门

原文链接: --> A guide to Python's function decorators Python功能强劲,语法表现力强,尤其装饰器深深的吸引着我.在设计模式中,装饰器可以在不使用子类的情况下,动态的改变函数,方法以及类的功能.这个功能非常有用,特别在你想扩展函数的功能同时又不想改变原有的函数.的确,我们任意的实现装饰器设计模式,但是,python通过提供简单的语法和特性让装饰器的实现变的如此简单. 在本文中,我将用一组例子来深入浅入python 函数装饰器的功能,所有的例子都是在