Python装饰器进阶
装饰器进阶
现在,我们已经明白了装饰器的原理。接下来,我们还有很多事情需要搞清楚。比如:装饰带参数的函数、多个装饰器同时装饰一个函数、带参数的装饰器和类装饰器。
装饰带参数函数
def foo(func): # 接收的参数是一个函数名
def bar(x, y): # 这里需要定义和被装饰函数相同的参数
print("这里是新功能...") # 新功能
func(x, y) # 被装饰函数名和参数都有了,就能执行被装饰函数了
return bar
# 定义一个需要两个参数的函数
@foo
def f1(x, y):
print("{}+{}={}".format(x, y, x+y))
# 调用被装饰函数
f1(100, 200)
输出:
这里是新功能...
100+200=300
多个装饰器
def foo1(func):
print("d1")
def inner1():
print("inner1")
return "<i>{}</i>".format(func())
return inner1
def foo2(func):
print("d2")
def inner2():
print("inner2")
return "<b>{}</b>".format(func())
return inner2
@foo1
@foo2
def f1():
return "Hello Andy"
# f1 = foo2(f1) ==> print("d2") ==> f1 = inner2
# f1 = foo1(f1) ==> print("d1") ==> f1 = foo1(inner2) ==> inner1
ret = f1() # 调用f1() ==> inner1() ==> <i>inner2()</i> ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i>
print(ret)
带参数装饰器
被装饰的函数可以带参数,装饰器同样也可以带参数。
回头看我们上面写得那些装饰器,它们默认把被装饰的函数当成唯一的参数。但是呢,有时候我们需要为我们的装饰器传递参数,这种情况下应该怎么办呢?
接下来,我们就一步步实现带参数的装饰器:
首先我们来回顾下上面的代码:
def f1(func): # f1是我们定义的装饰器函数,func是被装饰的函数
def f2(*arg, **kwargs): # *args和**kwargs是被装饰函数的参数
func(*arg, **kwargs)
return f2
从上面的代码,我们发现了什么?
我的装饰器如果有参数的话,没地方写了…怎么办呢?
还是要使用闭包函数!
我们需要知道,函数除了可以嵌套两层,还能嵌套更多层:
# 三层嵌套的函数1
def f1():
def f2():
name = "Andy"
def f3():
print(name)
return f3
return f2
嵌套三层之后的函数调用:
f = f1() # f --> f2
ff = f() # ff --> f3
ff() # ff() --> f3() --> print(name) --> Andy
注意:在内部函数f3中能够访问到它外层函数f2中定义的变量,当然也可以访问到它最外层函数f1中定义的变量。
# 三层嵌套的函数2
def f1():
name = "Andy"
def f2():
def f3():
print(name)
return f3
return f2
调用:
f = f1() # f --> f2
ff = f() # ff --> f3
ff() # ff() --> f3() --> print(name) --> Andy
好了,现在我们就可以实现我们的带参数的装饰器函数了:
# 带参数的装饰器需要定义一个三层的嵌套函数
def d(name): # d是新添加的最外层函数,为我们原来的装饰器传递参数,name就是我们要传递的函数
def f1(func): # f1是我们原来的装饰器函数,func是被装饰的函数
def f2(*arg, **kwargs): # f2是内部函数,*args和**kwargs是被装饰函数的参数
print(name) # 使用装饰器函数的参数
func(*arg, **kwargs) # 调用被装饰的函数
return f2
return f1
上面就是一个带参装饰器的代码示例,现在我们来写一个完整的应用:
def d(a=None): # 定义一个外层函数,给装饰器传参数--role
def foo(func): # foo是我们原来的装饰器函数,func是被装饰的函数
def bar(*args, **kwargs): # args和kwargs是被装饰器函数的参数
# 根据装饰器的参数做一些逻辑判断
if a:
print("欢迎来到{}页面。".format(a))
else:
print("欢迎来到首页。")
# 调用被装饰的函数,接收参数args和kwargs
func(*args, **kwargs)
return bar
return foo
@d() # 不给装饰器传参数,使用默认的'None'参数
def index(name):
print("Hello {}.".format(name))
@d("电影") # 给装饰器传一个'电影'参数
def movie(name):
print("Hello {}.".format(name))
if __name__ == '__main__':
index("Andy")
movie("Andy")
输出:
欢迎来到首页。
Hello Andy.
欢迎来到电影页面。
Hello Andy.
类装饰器和装饰类
类装饰器
除了用函数去装饰函数外,我们还可以使用类去装饰函数。
class D(object):
def __init__(self, a=None):
self.a = a
self.mode = "装饰"
def __call__(self, *args, **kwargs):
if self.mode == "装饰":
self.func = args[0] # 默认第一个参数是被装饰的函数
self.mode = "调用"
return self
# 当self.mode == "调用"时,执行下面的代码(也就是调用使用类装饰的函数时执行)
if self.a:
print("欢迎来到{}页面。".format(self.a))
else:
print("欢迎来到首页。")
self.func(*args, **kwargs)
@D()
def index(name):
print("Hello {}.".format(name))
@D("电影")
def movie(name):
print("Hello {}.".format(name))
if __name__ == '__main__':
index("Andy")
movie("Andy")
装饰类
我们上面所有的例子都是装饰一个函数,返回一个可执行函数。Python中的装饰器除了能装饰函数外,还能装饰类。
可以使用装饰器,来批量修改被装饰类的某些方法:
# 定义一个类装饰器
class D(object):
def __call__(self, cls):
class Inner(cls):
# 重写被装饰类的f方法
def f(self):
print("Hello Andy.")
return Inner
@D()
class C(object): # 被装饰的类
# 有一个实例方法
def f(self):
print("Hello world.")
if __name__ == '__main__':
c = C()
c.f()
</div>
Python装饰器进阶的更多相关文章
- (转)python装饰器进阶一
Python装饰器进阶之一 先看例子 网上有很多装饰器的文章,上来说半天也没让人看明白装饰器到底是个什么,究竟有什么用,我们直接来看几个例子. Python递归求斐波那契数列 def fibonacc ...
- (转)python装饰器二
Python装饰器进阶之二 保存被装饰方法的元数据 什么是方法的元数据 举个栗子 def hello(): print('Hello, World.') print(dir(hello)) 结果如下: ...
- Python函数--装饰器进阶
开放封闭原则 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新功能. 2.对修改是封 ...
- day 12 - 1 装饰器进阶
装饰器进阶 装饰器的简单回顾 装饰器开发原则:开放封闭原则装饰器的作用:在不改变原函数的调用方式的情况下,在函数的前后添加功能装饰器的本质:闭包函数 装饰器的模式 def wrapper(func): ...
- Python—装饰器详解
装饰器:(语法糖) 本质是函数,它是赋予函数新功能,但是不改变函数的源代码及调用方式 原则: 1.不能修改被装饰函数的源代码 2.不能修改被装饰函数的调用方式 3.函数的返回值也不变 这两点简而言 ...
- day4之装饰器进阶、生成器迭代器
装饰器进阶 带参数的装饰器 # 某一种情况# 500个函数加装饰器, 加完后不想再加这个装饰器, 再过一个季度,又想加上去# 你可以设计你的装饰器,来确认是否执行 # 第一种情况 # 想要500个函数 ...
- 五分钟学会Python装饰器,看完面试不再慌
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第12篇文章,我们来看看Python装饰器. 一段囧事 差不多五年前面试的时候,我就领教过它的重要性.那时候我Pyt ...
- Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方案
本文为霍格沃兹测试学院学员学习笔记. Python 装饰器简介 装饰器(Decorator)是 Python 非常实用的一个语法糖功能.装饰器本质是一种返回值也是函数的函数,可以称之为“函数的函数”. ...
- 关于python装饰器
关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...
随机推荐
- 管理KVM虚拟机(二)
管理KVM虚拟机 工具:libvirt 官网:http://libvirt.org/ 介绍:Libvirt 库是一种实现 Linux 虚拟化功能的 Linux® API,它支持各种虚拟机监控程序,包括 ...
- INF文件详解
安装信息(Setup Information)文件是Windows系统支持的一种安装信息存放文件,一般以INF作为扩展名,因此也叫INF文件.安装信息INF文件与Windows内建的安装服务引擎(AP ...
- FastDFS简单入门小demo
图片上传 需要引入 FastDFS 相关的jar包,但是这个jar没有在中央仓库,所以还得需要找到这个jar手动安装到自己的本地仓库才能使用. 需要一个配置文件 fdfs_client.conf ...
- 自定义泛型_无多态_通配符无泛型数组_jdk7泛型使用
通配符 T, K, V, E 等泛型字母为有类型, 类型参数赋予具体的值 ? 未知类型 类型参数赋予不确定值, 任意类型 只能用在 声明类型上,方法参数上, 不能用在定义泛型类上 上限 extends ...
- 基于JWT(Json Web Token)的ASP.NET Web API授权方式
token应用流程 初次登录:用户初次登录,输入用户名密码 密码验证:服务器从数据库取出用户名和密码进行验证 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT 返还JWT ...
- [转载]DOMContentLoaded与interactive
http://www.cnblogs.com/muxrwc/archive/2011/01/13/1934379.html ie中inline script执行时竟然第一次进入页面,doc.ready ...
- css框架,一把锋利的剑
CSS 框架是一系列 CSS 文件的集合体,包含了基本的元素重置,页面排版.网格布局.表单样式.通用规则等代码块,用于简化web前端开发的工作,提高工作效率. 产生原因 互联网行业已经发展了多年,浏览 ...
- PHP中GET和POST区别
1. get是从服务器上获取数据,post是向服务器传送数据.2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.post是通过H ...
- J - FatMouse's Speed dp
题目链接: https://vjudge.net/contest/68966#problem/J 找最长子串并且记录路径. TLE代码: #include<iostream> #inclu ...
- linux磁盘空间查看inode
服务器一般是要求长期连续运行的,自动执行任务生成的各种文件及日志,可能使空间占满,从而造成业务故障,所以要定时清理. 一般来说,Linux空间占满有如两种情况: 1.空间被占满了 用df -k 可以看 ...