• 装饰器基础
  • 函数引用
  • 手工装饰器
  • 装饰器阐述
  • 装饰器高级用法
    • 1 给装饰器函数传递函数
    • 2 装饰方法

1. 装饰器:基础

python 中一切皆是对象,这里需要强调 函数是对象。为了更好地理解函数也是对象,下面结合代码片段来说明这一点。


def shout(word="yes"):return word.capitalize() + "!"print shout()
# outputs: Yes!"""
As an object, you can assign the function to a variable like any other object.
Notice we don't use parentheses: we are not calling the function,
we are putting the function "shout" into the variable "scream".
"""
scream = shoutprint scream()
# outputs: Yes!"""
More than that, it means you can remove the old name 'shout',
and the function will still be accessible from 'scream'.
"""
del shout
try:print shout()
except NameError, e:print e# outputs: name 'shout' is not definedprint scream()
# outputs: 'Yes!'

因为函数是对象,所以 python 中函数还有一个有趣的特性:函数可以被定义在另一个函数中。下面来看下具体的例子

def talk():# You can define a function on the fly in "talk"def whisper(word="yes"):return word.lower()+"..."print whisper()"""
You call "talk", that defines "whisper" EVERY TIME you call it,
then "whisper" is called in "talk".
"""
talk()
# outputs: yes...# But "whisper" DOES NOT EXIST outside "talk".
try:print whisper()
except NameError, e:print e# outputs : name 'whisper' is not defined

2 函数引用

前面已经知道了函数是对象。那么:
1. 可以被赋值给另一个变量
2. 可以被定义在另一个函数里

这也意味着,一个函数可以返回另一个函数,下面来看一个简单的例子


def shout(word="yes"):return word.capitalize() + "!"print shout()
# outputs: Yes!"""
As an object, you can assign the function to a variable like any other object.
Notice we don't use parentheses: we are not calling the function,
we are putting the function "shout" into the variable "scream".
"""
scream = shoutprint scream()
# outputs: Yes!"""
More than that, it means you can remove the old name 'shout',
and the function will still be accessible from 'scream'.
"""
del shout
try:print shout()
except NameError, e:print e# outputs: name 'shout' is not definedprint scream()
# outputs: 'Yes!'

我们来进一步挖掘一下函数的特性,既然可以返回函数,那么我们也可以把函数作为参数传递

def whisper(word="yes"):return word.lower() + "..."def do_something_before(func):print "I do something before."print "Now the function you gave me:\n", func()do_something_before(whisper)
"""outputs
I do something before.
Now the function you gave me:
yes...
"""

现在,了解装饰器所需要的所有要点我们已经掌握了,通过上面的例子,我们还可以看出装饰器其实就是封装器,可以让我们在不修改原函数的基础上,在执行原函数的前后执行别的代码。

3 手工装饰器

下面我们手工实现一个简单的装饰器

def my_shiny_new_decorator(a_function_to_decorate):"""Inside, the decorator defines a function on the fly: the wrapper.This function is going to be wrapped around the original functionso it can execute code before and after it."""def the_wrapper_around_the_original_function():"""Put here the code you want to be executed BEFORE the originalfunction is called"""print "Before the function runs"# Call the function here (using parentheses)a_function_to_decorate()"""Put here the code you want to be executed AFTER the originalfunction is called"""print "After the function runs""""At this point, "a_function_to_decorate" HAS NEVER BEEN EXECUTED.We return the wrapper function we have just created.The wrapper contains the function and the code to execute beforeand after. It’s ready to use!"""return the_wrapper_around_the_original_function# Now imagine you create a function you don't want to ever touch again.
def a_stand_alone_function():print "I am a stand alone function, don't you dare modify me"a_stand_alone_function()
# outputs: I am a stand alone function, don't you dare modify me"""
Well, you can decorate it to extend its behavior.
Just pass it to the decorator, it will wrap it dynamically in
any code you want and return you a new function ready to be used:
"""a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
"""outputs:
Before the function runs
I am a stand alone function, don't you dare modify me
After the function runs
"""

现在,如何我们想每次调用 a_stand_alone_function 的时候,实际上调用的是封装后的函数 a_stand_alone_function_decorated,那么只需要用 a_stand_alone_function去覆盖my_shiny_new_decorator 返回的函数即可。也就是:

a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)

4 装饰器阐述

对于前面的例子,如果用装饰器语法,可以添加如下:

@my_shiny_new_decorator
def another_stand_alone_function():print "Leave me alone"another_stand_alone_function()
"""outputs:
Before the function runs
Leave me alone
After the function runs
"""

以上就是装饰器语法。这里的 @my_shiny_new_decoratoranother_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function) 的简写。

装饰器只是装饰器设计模式的 python 实现,python 还存在其他几个经典的涉及模式,以方便开发,例如迭代器 iterators。

当然了,我们也可以嵌套装饰器

def bread(func):def wrapper():print "</''''''\>"func()print "<\______/>"return wrapperdef ingredients(func):def wrapper():print "#tomatoes#"func()print "~salad~"return wrapperdef sandwich(food="--ham--"):print foodsandwich()
# outputs: --ham--
sandwich = bread(ingredients(sandwich))
sandwich()
"""outputs:
</''''''\>#tomatoes#--ham--~salad~
<\______/>
"""

用 python 的装饰器语法,如下:

@bread
@ingredients
def sandwich_2(food="--ham_2--"):print foodsandwich_2()

5 装饰器高级用法

5.1 给装饰器函数传递函数

当我们调用装饰器返回的函数时,其实是在调用封装函数,给封装函数传递参数也就同样的给被装饰函数传递了参数。

def a_decorator_passing_arguments(function_to_decorate):def a_wrapper_accepting_arguments(arg1, arg2):print "I got args! Look:", arg1, arg2function_to_decorate(arg1, arg2)return a_wrapper_accepting_arguments"""
Since when you are calling the function returned by the decorator, you are
calling the wrapper, passing arguments to the wrapper will let it pass them to
the decorated function
"""@a_decorator_passing_arguments
def print_full_name(first_name, last_name):print "My name is", first_name, last_nameprint_full_name("Peter", "Venkman")
"""outputs:
I got args! Look: Peter Venkman
My name is Peter Venkman
"""

5.2 装饰方法

python 中函数和方法几乎一样,处理方法中第一个参数是指向当前对象的引用(self)。这意味着我们可以为方法创建装饰器,只是要记得考虑 self。

def method_friendly_decorator(method_to_decorate):def wrapper(self, lie):lie = lie - 3return method_to_decorate(self, lie)return wrapperclass Lucy(object):def __init__(self):self.age = 32@method_friendly_decoratordef sayYourAge(self, lie):print "I am %s, what did you think?" % (self.age + lie)l = Lucy()
l.sayYourAge(-3)
# outputs: I am 26, what did you think?

我们还可以创建一个通用的装饰器,可以用于所有的方法或者函数,而且不用考虑它的参数情况。这时候,我们要用到 *args, **kwargs

def a_decorator_passing_arbitrary_arguments(function_to_decorate):# The wrapper accepts any argumentsdef a_wrapper_accepting_arbitrary_arguments(*args, **kwargs):print "Do I have args?:"print argsprint kwargs# Then you unpack the arguments, here *args, **kwargs# If you are not familiar with unpacking, check:# http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/function_to_decorate(*args, **kwargs)return a_wrapper_accepting_arbitrary_arguments

2. Python decorate相关推荐

  1. python装饰器类-Python 装饰器装饰类中的方法

    title: Python 装饰器装饰类中的方法 comments: true date: 2017-04-17 20:44:31 tags: ['Python', 'Decorate'] categ ...

  2. python装饰器实例-基于Python 装饰器装饰类中的方法实例

    title: Python 装饰器装饰类中的方法 comments: true date: 2017-04-17 20:44:31 tags: ['Python', 'Decorate'] categ ...

  3. Python 闭包、单个装饰器、多个装饰器、装饰器修饰类、应用场景

    1. 闭包 在 Python 中,函数也可以作为参数.我们可以执行下面的代码: def func(a, b):return a + bprint(func) 我们直接输出函数名,而没有加括号.输出结果 ...

  4. 【Python line_profiler memory_profiler】分析每一行代码的耗时及内存占用情况

    一.Python 借助 line_profiler 模块 查看每一行耗了多少时间? 1. 安装 windows10.python3.7.4安装,安装得个2分钟左右 pip install line_p ...

  5. 如何使用Python的进度条?

    在使用Python处理比较耗时操作的时候,为了便于观察处理进度,就需要通过进度条将处理情况进行可视化展示,以便我们能够及时了解情况.这对于第三方库非常丰富的Python来说,并不是什么难事. tqdm ...

  6. 整理了 70 个 Python 面向对象编程案例,怎能不收藏?

    作者 | 周萝卜 来源 | 萝卜大杂烩 Python 作为一门面向对象编程语言,常用的面向对象知识怎么能不清楚呢,今天就来分享一波 文章很长,高低要忍一下,如果忍不了,那就收藏吧,总会用到的 在 Py ...

  7. 数据分析最有用的Top 50 Matplotlib图(带有完整的Python代码)(上)

    CSDN博客 作者:zsx_yiyiyi 编辑:python大本营 50个Matplotlib图的汇编,在数据分析和可视化中最有用.此列表允许您使用Python的Matplotlib和Seaborn库 ...

  8. 【廖雪峰python进阶笔记】函数式编程

    1. 高阶函数 高阶函数就是可以把函数作为参数的函数,下面我们看一个简单的高阶函数: def add(x, y, f):return f(x) + f(y) 如果传入abs作为参数f的值: add(- ...

  9. 25个常用Matplotlib图的Python代码,收藏收藏!

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 大家好,小白今天分享给大家25个Matplotlib图的汇总,在数 ...

  10. Python 爬取北京二手房数据,分析北漂族买得起房吗?(附完整源码)

    来源:CSDN 本文约3500字,建议阅读9分钟. 本文根据Python爬取了赶集网北京二手房数据,R对爬取的二手房房价做线性回归分析,适合刚刚接触Python&R的同学们学习参考. 房价高是 ...

最新文章

  1. 飞越难关,飞书生态「战疫工具箱」来驰援!
  2. 【python开源项目】推荐一款prize万能抽奖小工具发布
  3. 022 Spark shuffle过程
  4. windows下的eclipse运行hdfs程序时报错 (null) entry in command string: null chmod 0644【笔记自用】
  5. 深入分析 Flutter 初始化流程
  6. C/C++ strict-aliasing
  7. 如何在linux程序中捕获异常信号
  8. 12个Visual Studio调试效率技巧
  9. java scanner转string,Java InputStream to String 转化
  10. Android 7.0后 播放U盘中的视频文件的解决方案
  11. Go实现短url项目
  12. MFC---CComboBox控件添加字符串函数InsertString
  13. android 卡片消息,安卓QNotified 支持xml卡片QQ消息 - 陌路人博客
  14. 如何做一场B格满满的技术大会演讲
  15. Vue项目url中的BASE_URL解析
  16. python定向爬虫之淘宝商品比价
  17. S-003 MIPI接口与LVDE接口的区别
  18. 永远的疯狂竹子----纪念退役不久的V-Gundam
  19. MySQL自动删除指定时间以前的记录
  20. 迷失在森林里的小女孩

热门文章

  1. 新增收货地址管理 html,关于“收货地址”的二三事
  2. 学编程c语言高考能加分吗,编程已列入中高考,孩子升学加分的机会能否抓住?...
  3. 织梦上传到服务器不显示图像,织梦dede源码前台会员发布文章带图片不显示怎么办?...
  4. Gartner 魔力四象限
  5. 微信扫描下载apk解决方案
  6. R语言 formula()
  7. “线上食堂”项目报告
  8. 4D 语义分割——TemporalLidarSeg
  9. 在PyG上构建自己的数据集
  10. PyG框架:Graph Classification