此系列文档:

1. 我终于弄懂了Python的装饰器(一)

2. 我终于弄懂了Python的装饰器(二)

3. 我终于弄懂了Python的装饰器(三)

4. 我终于弄懂了Python的装饰器(四)

一、装饰器基础(什么是装饰器)

Python的函数是对象

要了解装饰器,您必须首先了解函数是Python中的对象。这具有重要的联系。

让我们来看一个简单的例子:

def shout(word="yes"):
return word.capitalize()+"!" print(shout())
# 输出 : 'Yes!' # 作为一个对象,您可以像其他对象一样将函数赋给变量
scream = shout #注意我们不使用括号:我们没有调用函数
#我们将函数“shout”放入变量“scream”。
#这意味着您可以从“scream”中调用“shout”: print(scream())
# 输出: 'Yes!' #除此之外,这意味着您可以删除旧名称'shout',该功能仍可从'scream'访问 del shout try:
print(shout())
except NameError as e:
print(e)
#输出: "name 'shout' is not defined" print(scream())
# 输出: 'Yes!'

请记住这一点,我们将在不久后回头再说。

Python函数的另一个有趣特性是可以在另一个函数中定义它们!

def talk():

    # 您可以在“talk”中动态定义一个函数...
def whisper(word="yes"):
return word.lower()+"..." # ...并且可以立马使用它。
print(whisper()) #您每次调用“talk”,都会定义“whisper”,然后在“talk”中调用“whisper”。 talk()
# 输出:
# "yes..." # 但是"whisper"不存在"talk"定义以外的地方: try:
print(whisper())
except NameError as e:
print(e)
#输出 : "name 'whisper' is not defined"

函数参考

OK,应该还在看吧?现在开始有趣的部分...

您已经看到函数是对象。

因此,函数:

  • 可以分配给变量
  • 可以在另一个函数中定义

这意味着一个函数可以return另一个功能

def getTalk(kind="shout"):

    # 我们顶一个即时的函数
def shout(word="yes"):
return word.capitalize()+"!" def whisper(word="yes") :
return word.lower()+"..."; # 然后我们返回它
if kind == "shout":
#我们不使用“()”,所以我们没有调用函数,我们正在返回这个函数对象
return shout
else:
return whisper #获取函数并将其分配给变量: "talk"
talk = getTalk() #您可以看到“talk”是一个函数对象:
print(talk)
#输出 : <function shout at 0xb7ea817c> #函数对象返回的内容:
print(talk())
#输出 : Yes! #如果您感到困惑,甚至可以直接使用它:
print(getTalk("whisper")())
#outputs : yes...

还有更多的内容!

如果可以return一个函数,则可以将其中一个作为参数传递:

def doSomethingBefore(func):
print("I do something before then I call the function you gave me")
print(func()) doSomethingBefore(scream)
#输出:
#I do something before then I call the function you gave me
#Yes!

好吧,您只具备了解装饰器所需的所有信息。

您会看到,装饰器是“包装器(wrappers)”,这意味着它们使您可以在装饰函数之前和之后执行代码,而无需修改函数本身的代码内容。

手工进行装饰

您将知道如何进行手动操作:

#装饰器是讲另外一个函数作为参数的函数
def my_shiny_new_decorator(a_function_to_decorate): # 在内部,装饰器动态定义一个函数:包装器(wrappers)。
# 此功能将被包装在原始功能的外部,以便它可以在代码之前和之后执行代码。
def the_wrapper_around_the_original_function(): # 在调用原始函数之前,将要执行的代码放在此处
print("Before the function runs") #在此处调用函数(使用括号)
a_function_to_decorate() # 在调用原始函数后,将要执行的代码放在此处
print("After the function runs") #至此,“a_function_to_decorate”从未执行过。
#我们返回刚刚创建的包装函数。
#包装器包含函数和在代码之前和之后执行的代码。随时可以使用!
return the_wrapper_around_the_original_function #现在,假设您创建了函数,但是不想再修改的函数。
def a_stand_alone_function():
print("I am a stand alone function, don't you dare modify me") a_stand_alone_function()
#输出: I am a stand alone function, don't you dare modify me #所以,您可以装饰它以扩展其行为。
#只需将其传递给装饰器,它将动态地包装在
#您想要的任何代码中,并为您返回准备使用的新功能: a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated() #输出:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

现在,您可能希望每次调用a_stand_alone_functiona_stand_alone_function_decorated都调用它。

这很简单,只需a_stand_alone_function用以下方法返回的函数覆盖my_shiny_new_decorator

a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#输出:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs #这正是装饰器的工作!

装饰器神秘化

这里展示一下使用装饰器的语法:

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

是的,仅此而已。@decorator只是实现以下目的的捷径:

another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)

装饰器只是装饰器设计模式的pythonic变体。

Python中嵌入了几种经典的设计模式来简化开发(例如迭代器)。

当然,您可以累加装饰器:

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

使用Python装饰器语法:

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

您设置装饰器事项的顺序是很重要的,如::

@ingredients
@bread
def strange_sandwich(food="--ham--"):
print(food) strange_sandwich()
#outputs:
##tomatoes#
#</''''''\>
# --ham--
#<\______/>
# ~salad~

本文首发于BigYoung小站

我终于弄懂了Python的装饰器(一)的更多相关文章

  1. 我终于弄懂了Python的装饰器(二)

    此系列文档: 1. 我终于弄懂了Python的装饰器(一) 2. 我终于弄懂了Python的装饰器(二) 3. 我终于弄懂了Python的装饰器(三) 4. 我终于弄懂了Python的装饰器(四) 二 ...

  2. 我终于弄懂了Python的装饰器(四)

    此系列文档: 1. 我终于弄懂了Python的装饰器(一) 2. 我终于弄懂了Python的装饰器(二) 3. 我终于弄懂了Python的装饰器(三) 4. 我终于弄懂了Python的装饰器(四) 四 ...

  3. 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档

    转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...

  4. 进阶Python:装饰器 全面详解

    进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用 ...

  5. Python各式装饰器

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  6. Python札记 -- 装饰器补充

    本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...

  7. python基础——装饰器

    python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...

  8. 【转】详解Python的装饰器

    原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...

  9. 两个实用的Python的装饰器

    两个实用的Python的装饰器 超时函数 这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 .网络爬虫.数据库查询的时候特别有用 timeout装饰器的代码 ...

随机推荐

  1. Android数据库框架-ORMLite

    参考资料 Android ORMLite 框架的入门用法 Android 快速开发系列 ORMLite 框架最佳实践 添加依赖 compile 'com.j256.ormlite:ormlite-an ...

  2. ArrayList、LinkedList、Vector、Array和HashMap、HashTable

    就 ArrayList 与 Vector 主要从二方面来说. 一.同步性:Vector 是线程安全的,也就是说是同步的,而ArrayList 是线程序不安全的,不是同步的 二.数据增长:当需要增长时, ...

  3. 前端JS的服务订阅&服务发布

    var eventCenter = { sub:function(mesName, mesCallback){ this.argus=this.argus||{}; this.argus[mesNam ...

  4. Jmeter使用beanshell对数据进行加密传输

    首先,来看一下接口签名加密规则 1.需要参于签名的参数: a. 在请求参数列表中,除去 cliSign 参数外,其他需要使用到的参数皆是要签名的参数. 2.生成签名字符串 a. 没有值的参数无需传递, ...

  5. MSSQL(DAC环境一下一些特殊的访问方式)

    MSSQL(在DAC环境下访问: 存储过程) Server name:      admin:计算机名\实例名                 or       admin:IP地址\实例名      ...

  6. Mybatis源码手记-从缓存体系看责任链派发模式与循环依赖企业级实践

    一.缓存总览 Mybatis在设计上处处都有用到的缓存,而且Mybatis的缓存体系设计上遵循单一职责.开闭原则.高度解耦.及其精巧,充分的将缓存分层,其独到之处可以套用到很多类似的业务上.这里将主要 ...

  7. maven配置错误之Unable to import maven project: See logs for details

    很多朋友在初次使用maven时,都会出现这个问题. 一加载maven项目,即会报出Unable to import maven project这样的错误,哪怕是新的maven项目也不例外. 我查阅了很 ...

  8. selenium(3)-针对鼠标的操作

    背景 用selenium做自动化,有时候会遇到需要模拟鼠标操作才能进行的情况,比如单击.双击.点击鼠标右键.拖拽等等. 而selenium给我们提供了一个类来处理这类事件-----------Acti ...

  9. elasticsearch中query和filter的区别

    参考博客来自: https://mp.weixin.qq.com/s/tiiveCW3W-oDIgxvlwsmXA?utm_medium=hao.caibaojian.com&utm_sour ...

  10. 实时web应用方案——SignalR(.net core)

    何为实时 先从理论上解释一下两者的区别. 大多数传统的web应用是这样的:客户端发起http请求到服务端,服务端返回对应的结果.像这样: 也就是说,传统的web应用都是客户端主动发起请求到服务端. 那 ...