python-装饰器的简单使用
一、介绍
首先我们先来看一个简单的例子,在基础平台中有一个home()和tv()函数,在业务平台中调用此函数时,给出了响应的打印内容:
基础平台:
def home():
print('welcome to home page')
def tv(name):
print('welcome to tv page') 业务平台A:
home()
tv() 业务平台B:
home()
tv()
但是,在后续的需求中规定,在调用此函数时,还需要进行一个用户验证
因此程序猿小A的做法是和每个业务部门交涉,每个业务部门自己写代码,在调用基础平台的时候,先进行验证:
基础平台:
def home():
print('welcome to home page')
def tv(name):
print('welcome to tv page') 业务平台A:
#验证
home()
tv() 业务平台B:
#验证
home()
tv()
小A当天被开除了。。。
后来程序猿小B接手了这份工作,小B的做法是在基础平台中加入验证:
基础平台:
def home():
#验证
print('welcome to home page')
def tv(name):
#验证
print('welcome to tv page') 业务平台A:
home()
tv() 业务平台B:
home()
tv()
小B的做法相比于小A来说,好了一点,避免了业务平台的修改,老板为了奖励小B,因此在一周后把小B开除了。。。
因为小B改动了源代码
此后,程序猿小C又接受了这个工作。。。
小C说:
写代码要满足以下下两个原则:
封闭:已实现的功能代码不允许被修改
开放:已实现的功能代码可以被扩展:
因此,小C打算在此处使用了装饰器的功能(见下文)
总结:
装饰器本质上是一个函数,可以在其他函数不做任何代码变动的情况下,提供一些扩展的功能
二、简单装饰器的使用
小C对代码做出了如下修改(拿tv方法举例):
def login(func): #定义了一个登录验证的方法
print('登录验证成功') #假设此处就是一个验证功能
return func def tv():
print('welcome to tv page' )
tv=login(tv) #对tv进行了赋值,此时还没执行tv方法,只是把该方法放入到了内存中 tv() ---执行结果---
登录验证成功
welcom to tv page
该代码是如何实现验证的呢,步骤如下:
①执行login(tv)时,先不执行tv()方法,只是把tv()方法到了内存中,然后执行login()
②在login()中进行登录验证,之后返回tv()的内存地址,此时tv()还未执行
③把tv()的内存地址重新赋值给tv,此时tv变量的值依旧为tv()方法的内容
④通过调动tv()执行tv()方法
再经过一些细小的调整,可以写成如下的形式:
def login(func):
print('登录验证成功')
return func @login
def tv():
print('welcome to tv page' ) tv()
其中, @XXX 语法,就是一个装饰器,也称为“语法糖”
至此,一个简单的装饰器雏形已经完成
但是,此处依旧有一个缺点,那就是 即使业务方没有调用tv(),代码中也依旧会执行login()中的验证,为了让login()中的验证
不预先执行,因此小C继续对代码进行调整
def login(func):
def inner():
print('登录验证成功')
func()
return inner @login
def tv():
print('welcome to tv page' ) tv()
此处实现验证功能的步骤如下:
①调用login()方法,返回inner方法的内存地址,此时func的值为tv()内存地址即内容为:
def tv():
print('welcome to tv page' )
②把inner方法的内存地址赋值给了变量tv
③调用tv(),因为tv的值已经为inner的内存地址,因此调用的是inner()方法
④实现inner()中的验证功能
⑤验证成功后,执行inner()中的func(),打印出‘welcome to tv page’
至此,一个简单的装饰器才算真正完成
如果想在调用方法中实现带参数,可以这样写:
def login(func):
def inner(arg):
print('登录验证成功')
func(arg)
return inner @login
def tv(name):
print('welcom to [%s] tv page' %name ) @login
def movie(name):
print('welcom to [%s] movie page' %name ) tv('nee')
movie('nee') -----结果-----
登录验证成功
welcom to [nee] tv page
登录验证成功
welcom to [nee] movie page
在上面的例子中,都是实现了在调用tv()和movie()时带入一个参数的情况的。但如果在调用tv()时需要一个参数,在调用movie()时用两个参数呢?
因此可以使用一个动态参数的方法:
def login(func):
def inner(*args): #代表动态参数
print('登录验证成功')
func(*args)
return inner @login
def tv(name,password):
print('welcom to [%s] tv page' %name ) @login
def movie(name):
print('welcom to [%s] movie page' %name ) tv('nee',123456)
movie('nee')
如果再进一步,想要在调用tv()方法后,打印一个结果
def login(func):
def inner(*args,**kwargs):
print('登录验证成功')
return func(*args,**kwargs) #注意此处的return
return inner @login
def tv(name,password):
print('welcom to [%s] tv page' %name )
return '我最帅' a=tv('nee',password=123456)
print(a) -----结果-----
登录验证成功
welcom to [nee] tv page
我最帅
python-装饰器的简单使用的更多相关文章
- python装饰器的简单理解
如果你接触 Python 有一段时间了的话,想必你对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖. 装饰器的使用方法很固定: 先定义一个装饰函数(帽子)(也可以用类.偏函数实现) 再定义你 ...
- python 装饰器、内部函数、闭包简单理解
python内部函数.闭包共同之处在于都是以函数作为参数传递到函数,不同之处在于返回与调用有所区别. 1.python内部函数 python内部函数示例: def test(*args): def a ...
- Python中的装饰器的简单介绍02
这篇博文转载自伯乐在线的12步轻松搞定python装饰器,重构成python3. 1. 函数 在python中,函数通过def关键字.函数名和可选的参数列表定义.通过return关键字返回值.我们举例 ...
- http://python.jobbole.com/85056/ 简单 12 步理解 Python 装饰器,https://www.cnblogs.com/deeper/p/7482958.html另一篇文章
好吧,我标题党了.作为 Python 教师,我发现理解装饰器是学生们从接触后就一直纠结的问题.那是因为装饰器确实难以理解!想弄明白装饰器,需要理解一些函数式编程概念,并且要对Python中函数定义和函 ...
- Python 装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...
- python 装饰器修改调整函数参数
简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...
- python 装饰器学习(decorator)
最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...
- Python装饰器详解
python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...
- 理解Python装饰器
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓存.权 ...
- Python装饰器由浅入深
装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...
随机推荐
- mybatis学习之分页
分页一般分为物理分页:先查询所有值再分页输出,逻辑分页:直接分页查询输出,mybatis支持物理分页,如下: 1.物理分页: mapper映射: <select id="findStu ...
- [Erlang]各种系统限制总结
Erlang本身对进程数,原子长度等没有限制,但为了提高性能和节省内存,总会在实际实现中和运行环境中作出一些限制. 1.进程数量 缺省情况下同时存在的最大Erlang进程数量不超过2^18=26214 ...
- Rabbit的直连交换机direct
直连交换机类型为:direct.加入了路由键routingKey的概念. 就是说 生产者投递消息给指定交换机的指定路由键. 只有绑定了此交换机指定路由键的消息队列才可以收到消息. 生产者: packa ...
- spring的事务传播行为
1.PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置. 比如说,ServiceB.methodB的事务级别定义为PRO ...
- Java List集合和哈希表
List集合和Set集合,先来看List集合. List集合存储元素的特点: 1.有序(List集合中的元素有下标):存进去是什么样,取出来还是什么样 2.可重复 可以结合以下的简单代码来看一看. i ...
- Java CAS总结
文章目录 1. CPU指令对CAS的支持(CPU的cas指令是原子的) 或许我们可能会有这样的疑问,假设存在多个线程执行CAS操作并且CAS的步骤很多,有没有可能在判断V和E相同后,正要赋值时,切换了 ...
- thinkphp注册并写入数据到数据库中
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- <Android 基础(十九)> CoordinatorLayout
介绍 CoordinatorLayout,中文翻译,协调布局,顾名思义,此布局中的子View之间,子View与父布局之间应该是可以协调工作的,如何协调,Behavior. 今天看下Android St ...
- 注册表----修改Win7登录界面
在进行操作前,需要准备好背景图片.对背景图片的要求有三点: (1)图片必须是JPG格式: (2)必须将图片命名为backgroundDefault; (3)图片的体积必须小于256KB. 按下[Win ...
- 安卓基础干货(六):安卓Activity的学习
AndroidManifest文件中的几个细节 结论: 1.一个应用程序可以创建多个桌面图标 2.创建快捷图标的方法: <intent-filter> //应用程序的入口 <acti ...