我终于弄懂了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_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)
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的装饰器(一)的更多相关文章
- 我终于弄懂了Python的装饰器(二)
此系列文档: 1. 我终于弄懂了Python的装饰器(一) 2. 我终于弄懂了Python的装饰器(二) 3. 我终于弄懂了Python的装饰器(三) 4. 我终于弄懂了Python的装饰器(四) 二 ...
- 我终于弄懂了Python的装饰器(四)
此系列文档: 1. 我终于弄懂了Python的装饰器(一) 2. 我终于弄懂了Python的装饰器(二) 3. 我终于弄懂了Python的装饰器(三) 4. 我终于弄懂了Python的装饰器(四) 四 ...
- 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档
转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...
- 进阶Python:装饰器 全面详解
进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用 ...
- Python各式装饰器
Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...
- Python札记 -- 装饰器补充
本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...
- python基础——装饰器
python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...
- 【转】详解Python的装饰器
原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...
- 两个实用的Python的装饰器
两个实用的Python的装饰器 超时函数 这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 .网络爬虫.数据库查询的时候特别有用 timeout装饰器的代码 ...
随机推荐
- 运用Navicat for MySQL进行MSSQL数据转移MYSQL
当前不同数据库进行数据转移已经不是一件麻烦事情,特别是有很多很方便的工具,而最近我在搜集各种数据时候,也需要进行大量的数据转移,并且数据库和所转移的数据库表都不同,这次给大家介绍个最简单的方法,就是使 ...
- java关键字final用法详解
final关键字在java中也是属于比较常用的一种,因此也算得上是一个比较重要的关键字,有必要对它进行深入的学习. 一.定义:用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成 ...
- 20行Python代码开发植物识别 app
这篇文章介绍如何用Python快速实现一个植物识别的app,家里养了几盆多肉还叫不上名字,正好拿来识别一下.实现这样一个app只需要20行左右的代码,先来看下效果: 另外,我也开发了微信小程序版本,大 ...
- SmokePing 快速搭建
SmokePing介绍 smokeping是来监控IDC机房网络质量情况,可以从监控图上的延时与丢包情况分辨出机房的网络是否稳定,是否为多线,是否为BGP机房以及到各城市的三个运行商网络各是什么情况. ...
- 使用jdk1.8 stream特性对参数名称进行排序
在对外对接的时候,通常会碰到签名方式, 然后签名的时候,要求按照参数名称进行排序. 比如参数为 c=22&a=1, 需要将结果排序为a=1&c=22, 然后再进行别的运算. 可以使用j ...
- jar 反编译工具
luyten windows版本的 链接:https://pan.baidu.com/s/1hp6gyvJSj_4h60dk5AZejA 密码:c4u7 之所以推荐它,是因为它能避免普通的编译工具jd ...
- Node.js躬行记(4)——自建前端监控系统
这套前端监控系统用到的技术栈是:React+MongoDB+Node.js+Koa2.将性能和错误量化.因为自己平时喜欢吃菠萝,所以就取名叫菠萝系统.其实在很早以前就有这个想法,当时已经实现了前端的参 ...
- pip安装报错: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy
pip安装报错 解决办法: pip install selenium -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
- MAC地址表、ARP缓存表、路由表及交换机、路由器基本原理
在网上找到了这篇讲述MAC地址,ARP协议和路由表的文章,如获至宝.一篇文章把组网中的相关概念讲的明明白白. 原文是发布在51cto博客上,但不知道为什么点进去却是404.让我没想到的是这个技术论坛上 ...
- Python 为什么推荐蛇形命名法?
关于变量的命名,这又是一个容易引发程序员论战的话题.如何命名才能更具有可读性.易写性与明义性呢?众说纷纭. 本期"Python为什么"栏目,我们将聚焦于变量命名中的连接方式,来切入 ...